I apologize if this has been asked before, but I don't even know what terms to search for. I'm a beginner with xml and xslt and am looking to create html output from a xml file. My problem looks like this:
The text in my xml file is:
<?xml version="1.0" encoding="UTF-8"?>
<body>
<p>This is some text. This is the last bit of text.</p>
<add>This is some other <hi>text</hi>.</add>
</body>
The output I want in my html is
<p>This is some text. This is some other <hi>text</hi>. This is the last bit of text.<p>
I cannot just tag
<?xml version="1.0" encoding="UTF-8"?>
<body>
<p><a>This is some text.</a> <b>This is the last bit of text.</b><p>
<c>This is some other <hi>text</hi>.</c>
</body>
What I want to do is place a marker for where the text needs to be inserted. Sort of like this:
<?xml version="1.0" encoding="UTF-8"?>
<body>
<p>This is some text. <insert n="1"/> This is the last bit of text.<p>
<addition n="1">This is some other <hi>text</hi>.</addition>
</body>
The added text can be anywhere in the document, but it I can easily assign the n manually. Any ideas how to achieve this with my xslt stylesheet?
Edit: In some cases the text within contains more tags with corresponding templates in the xsl. I tried solving this on my own, but could not figure out how to apply templates within a key, could someone point me to a solution?
Many thanks!
Marie
Let me modify your example a bit, because I suspect that wherever there is an <addition n="1">, there will eventually be an <addition n="2"> too.
Given the following example input:
<body>
<p>Four score and seven years ago our fathers brought forth, <insert n="1"/>a new nation, conceived in liberty, and dedicated to the proposition that “all men are created equal.”</p>
<p>Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived, and so dedicated, can long endure. <insert n="2"/>We come to dedicate a portion of it, as a final resting place for those who died here, that the nation might live. This we may, in all propriety do.</p>
<addition n="1">upon this continent, </addition>
<addition n="2">We are met on a great battle field of that war. </addition>
</body>
the following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="add" match="addition" use="#n" />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="insert">
<xsl:value-of select="key('add', #n)"/>
</xsl:template>
<xsl:template match="addition"/>
</xsl:stylesheet>
will return:
<?xml version="1.0" encoding="UTF-8"?>
<body>
<p>Four score and seven years ago our fathers brought forth, upon this continent, a new nation, conceived in liberty, and dedicated to the proposition that “all men are created equal.”</p>
<p>Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived, and so dedicated, can long endure. We are met on a great battle field of that war. We come to dedicate a portion of it, as a final resting place for those who died here, that the nation might live. This we may, in all propriety do.</p>
</body>
Edit:
In view of your added requirement, change:
<xsl:template match="insert">
<xsl:value-of select="key('add', #n)"/>
</xsl:template>
to:
<xsl:template match="insert">
<xsl:apply-templates select="key('add', #n)/node()"/>
</xsl:template>
Related
i am making a website that will feature many articles that will always be changing, i am trying to find a way to quickly change the text in these articles as i am the only person who knows the code in the company.
I was thinking of having a text document or something that has the articles text and when it gets changed so does the text on the site.I just dont know how to implement this.
sorry if its hard to understand what i mean, im not too familiar with sleep these days.
You don't need any dynamic server code like the other answers are suggesting. Either a "static site generator" (there are uncountably many, but that should give you something to Google if my main answer doesn't satisfy you) or a client-side scripting.
XSLT was designed for this exact problem. It can be run client-side or server-side with xsltproc (for compatibility with dumb clients). XSLT 1.0 is well-supported by all common browsers, though if you need EXSLT extensions in IE you had to add shims. Note that Webkit-based browsers can't do XSLT on file:// URLs, either set up a local HTTP server or use Firefox.
I have a minimal example site set up here that includes multiple files in
one page: https://o11c.github.io/foo-test/foo-root.xml
foo-style.xml:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/index">
<html>
<body>
<h2>Merge test</h2>
<table border="1">
<tr>
<th>Attr</th>
<th>Value</th>
</tr>
<xsl:apply-templates select="document(include/#name)"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="root">
<xsl:for-each select="foo">
<tr>
<td><xsl:value-of select="#x"/></td>
<td><xsl:value-of select="text()"/></td>
</tr>
</xsl:for-each>
</xsl:template>
<xsl:template name="identity">
<xsl:copy>
<xsl:for-each select="node()|#*">
<xsl:call-template name="identity"/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
foo-root.xml:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="foo-style.xslt"?>
<index>
<include name="foo-1.xml"/>
<include name="foo-2.xml"/>
</index>
foo-1.xml:
<?xml version="1.0"?>
<root>
<foo x="a">aa</foo>
<foo x="b">bb</foo>
<foo x="c">cc</foo>
</root>
foo-2.xml:
<?xml version="1.0"?>
<root>
<foo x="d">dd</foo>
<foo x="e">ee</foo>
<foo x="f">ff</foo>
</root>
Further resources:
XSLT 1.0 spec
XPath 1.0 spec - in particular the function reference
EXSLT extensions - node-set in particular is very useful.
xsltproc webpage
You could use wordpress, if you are building the site from scratch and not adding to an existing one. This will allow you to edit articles in a user friendly interface that will allow you to style the text and will be easier for other people in the company to edit as well. It's very fast to set up.
Or you could just keep the written text in the HTML file itself, but this may make it harder to maintain and style, and those not technical savvy may not be able to edit it or will end up breaking it.
Well you might do this using php and Mysql
You can easily display save the articles in mysql and you could create a simple user interface for the people respnsible for editing the code to edit it too easy
I'm working with a bowling website and a software program written for management of our bowling league scores. The software also allows us to write an article on the last bowling league day. Now I'm copying the article into HTML module on the website but since it's also implemented in the same XML output file as the scores I'd like to take it out as well with XSLT. I only don't know what are the commands for this... So I have no XSLT file I'm working with. If I look it up here or on google , there seem to be tons of ways to do it but every time there's a bunch of other code as well and I'm still a beginner...
Can anybody help me?
<Infos>
<Info>
<Title><![CDATA[THIS IS THE TITLE OF THE ARTICLE]]></Title>
<Text><![CDATA[THIS THE ARTICLE]]></Text>
</Info>
</Infos>
The CDATA piece contains text, I want it to display after applying
XSLT and determine the text outcome (bold, Italic and underlined) with
XSLT
The following stylesheet:
XSLT 1.0
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Infos">
<html>
<body>
<xsl:apply-templates select="Info"/>
</body>
</html>
</xsl:template>
<xsl:template match="Info">
<h2><xsl:value-of select="Title" /></h2>
<i><xsl:value-of select="Text" /></i>
</xsl:template>
</xsl:stylesheet>
when applied to your example input, will produce the following result:
<html>
<body>
<h2>THIS IS THE TITLE OF THE ARTICLE</h2>
<i>THIS THE ARTICLE</i>
</body>
</html>
rendered as:
I have the following xml:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="ping1.xsl"?>
<article>
<date>28/06/2000 12:30</date>
<title>Rescued penguins swim home</title>
<para><place>Cape Town</place> Some 150 penguins unaffected by the oil spill began
their long swim from Port Elizabeth in the Eastern Cape back to their breeding
habitat at Robben Island near Cape Town on Wednesday. </para>
<para>The penguins, who have all been tagged, were transported in a truck hired by
the <company>South African National Conservation of Coastal Birds
(Sanccob)</company> to Port Elizabeth on Tuesday night. </para>
<para>More than <link ref="www.newsrus.com/oilspill.html">400 tons of fuel oil
escaped from the bulk ore carrier Treasure</link> before divers were able to seal
the holds.</para>
<para>The ship was carrying 130 000 tons of iron ore and 1 300 tons of fuel oil
when she sank off the Cape West coast last Friday. </para>
<para>A spokesperson for <company>Sanccob</company>, Christina Pretorius said
the centre had a capacity to treat 1 000 penguins. </para>
<source>John Rolfe</source>
</article>
I need to transform it in the following html form (you have the image of the HTML form):
The problem is I don't know how to apply templates on the para element and its sons element to get the output described in the image above.
Till now I have only:
<?xml version="1.0" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="ISO-8859-1" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
<xsl:template match='/'>
<HTML>
<BODY>
<xsl:apply-templates />
</BODY>
</HTML>
</xsl:template>
<xsl:template match="date">
<b><xsl:value-of select="."/></b>
<br/>
</xsl:template>
<xsl:template match="title">
<font color="blue"><xsl:value-of select="."/></font>
<br/>
<br/>
</xsl:template>
<xsl:template match="para">
<xsl:value-of select="."/><br/>
</xsl:template>
</xsl:stylesheet>
PS: I don't really care about the exact html style. You can also make it much more simplier. I just need to know how to apply templates to the para element and its sons and have the output as described in the image.
PS2: No for-each is allowed. Only templates and apply-templates. It is an exercise with respect to an assignment and it asks minimal use of templates and no for-each
It seems that you need to use <xsl:for-each> inside the <xsl:template match="para">
e.g.:
<xsl:for-each select="place">
(of course this is not the only solution, but it is what it comes to my mind)
Because you mentioned that it's an exercise, I wouldn't like to give a full solution, but maybe something you can work with: when you add the following templates (and replacing the <xsl:template match="para">) to your XSLT
<xsl:template match="para">
<p>
<xsl:apply-templates />
</p>
</xsl:template>
<xsl:template match="link">
<a>
<xsl:attribute name="href" select="#ref"/>
<xsl:apply-templates />
</a>
</xsl:template>
<xsl:template match="company | source">
<span style="font-weight:bold; font-style:normal;">
<xsl:apply-templates />
</span>
</xsl:template>
this output (only part of it as example) is created:
<p>The penguins, who have all been tagged, were transported in a truck hired by the
<span style="font-weight:bold; font-style:normal;">South African National Conservation
of Coastal Birds (Sanccob)</span> to Port Elizabeth on Tuesday night.
</p>
<p>More than <a href="www.newsrus.com/oilspill.html">400 tons of fuel oil escaped
from the bulk ore carrier Treasure</a> before divers were able to seal the holds.
</p>
The template matching para creates a <p> element and applies templates to the content of the para element. The template matching link creates an <a> tag with the href value of the ref attribute. The template matching company and source elements creates a <span> with a bold and normal font style (here you could also use css classes instead of inline styles), as most of the copy in the desired output is italic.
So you can just use templates matching the input elements to create HTML tags and apply the appropriate inline styles or add classes to get the desired output.
I'm using XSLT stylesheet to render a simple XML file of the text of Alice in Wonderland into HTML.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="Alice.xsl"?>
<book>
<title>Alice's Adventures in Wonderland</title>
<text>
<chapter>
<chapter_heading>Chapter I. Down the Rabbit-Hole</chapter_heading>
<p>Alice was beginning to get very tired of sitting by her sister on the
bank, and of having nothing to do: once or twice she had peeped into the
book her sister was reading, but it had no pictures or conversations in
it, 'and what is the use of a book,' thought Alice 'without pictures or
conversations?'</p>
<p>So she was considering in her own mind (as well as she could, for the
hot day made her feel very sleepy and stupid), whether the pleasure
of making a daisy-chain would be worth the trouble of getting up and
picking the daisies, when suddenly a White Rabbit with pink eyes ran
close by her.</p>
</chapter>
</text>
</book>
Simple stuff. And we're trying to output just the Title of the Chapter and the paragraphs into an tag in HTML using this code:
<?xml version="1.0" encoding="UTF-8"?><!-- DWXMLSource="http://www.w3.org/1999/XSL/Transform" -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8"/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<article>
<xsl:apply-templates/>
</article>
</body>
</html>
</xsl:template>
<xsl:template match="title"/>
<xsl:template match="chapter">
<h3>
<xsl:apply-templates select="chapter_heading"/>
</h3>
<div class="paragraph">
<xsl:apply-templates select="p"/>
</div>
</xsl:template>
</xsl:stylesheet>
But once the XML file is opened in a browser, all of the separate 'p' tags in the XML are just grouped together into one large 'div' in the HTML.
Our group is obviously very new to XSL, but as far as we've been able to research, we don't tell why this isn't working smoothly. Any help would be appreciated!
You dind't define a template for the <p> element.
You effectively applied templates on <p> elements with your <xsl:apply-templates select="p"/> but without a specific template for them, the xslt processor simply applies default template wich just output the text content of the elements. This is why you got everything in the same <div class='paragraph'> element (which is the parent element you create before applying template on <p>).
I guess, you want to preserve the <p> elements as they are in the input, then just add the template declaration below and you'll get your <p> in your output.
<xsl:template match="p">
<xsl:copy-of select="."/>
</xsl:template>
As a general design template, when you want to copy an input with some layout features, use a "copy template pattern" with this default declarations which will work for any input (<p> <citation> and so on).
<!-- This match will select any element without any other template matching (the `<p>` elements in your case.)-->
<xsl:template match="*">
<!-- First copy the element itself -->
<xsl:copy>
<!-- Then copy the attributes if any. -->
<xsl:copy-of select="#*">
<!-- Finally apply-templates on childs, then text nodes will be outputed by default templates, and elements would go through your template flow allowing to be copied or formatted if needed (with specific templates) -->
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
I don't know too much about XSL but have managed to format XML coming from 3rd party web services using XSL without too much trouble. But the other day, a site that used to work stopped working. I discovered that they made a tiny change to the XML returned by the web service. This is what used to work (greatly simplified):
Update: I see the problem now, but I don't have a solution. The problem is with xsl:if test="#xsi:type='r0:CreditTx'". Change every "r0" to "s0" in the XSL, and it does not work.
I have replaced my original code with a working example:
XML:
<?xml version="1.0" encoding="unicode"?>
<MyResp xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:r0="http://www.foo.com/2.1/schema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<r0:creditVendReceipt receiptNo="1234567890">
<r0:transactions>
<r0:tx xsi:type="r0:CreditTx">
<r0:amt value="100" />
</r0:tx>
</r0:transactions>
</r0:creditVendReceipt>
</MyResp>
XSL:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:r0="http://www.foo.com/2.1/schema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:template match="/">
<html>
<head>
</head>
<body >
<xsl:for-each select="MyResp/r0:creditVendReceipt/r0:transactions/r0:tx">
<xsl:if test="#xsi:type='r0:CreditTx'">
<xsl:value-of select="r0:amt/#value"/>
</xsl:if>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Desired HTML:
<html xmlns:r0="http://www.foo.com/2.1/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<head>
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
100
</body>
</html>
The problem came when the web service changed the xmlns' short name "a" to "a0" (it now sends xmlns:a0="http://mysite.com/webservice/1.0/schema"); the namespace and everything else is the same. I have to change "a" to "a0" in the XSL for it to work (i.e. "GetInfoResp/a0:userName"). The problem is that the short name sent by the service changes from time to time. (In the real app there are a lot of name spaces, and the short names are even changing between the various requests.)
I thought the short name was just to make the XML shorter and easier to read, and that the actual name isn't significant (betwen the XML and the XSL; within the XSL obviously it has to match).
Can I get the XSL to ignore the short name in the XML, and just use its own short name?
Sorry if this was answered before; I looked thru the other questions and didn't see this specific issue.
The "short name" is called a namespace prefix -- and you don't have to change the namespace prefix in the transformation -- in fact it may be completely different from any prefix that could be used in the XML document.
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xYz="http://mysite.com/webservice/1.0/schema"
exclude-result-prefixes="xYz">
<xsl:template match="/">
<html>
<body >
<xsl:value-of select="GetInfoResp/xYz:userName"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
produces exactly the same result as this transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:a0="http://mysite.com/webservice/1.0/schema"
exclude-result-prefixes="a0">
<xsl:template match="/">
<html>
<body >
<xsl:value-of select="GetInfoResp/a0:userName"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Both transformations, when applied on this XML document (what is provided in the question is severely malformed and had to be corrected):
<GetInfoResp xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:a0="http://mysite.com/webservice/1.0/schema">
<a0:userName>Joe</a0:userName>
</GetInfoResp>
produce the same result:
<html>
<body>Joe</body>
</html>
Lesson to learn:
What matters is the namespace, not the prefix used to shorthand it.