Trying to link use XSL to output a HTML table from XML - html

I'm trying to use a .xsl file so that it will return a HTML table of the XML document. I have no experience with this and it is something I've not done before so it's probably this is just a simple mistake.
I have the following code for my podcatalog.xsl
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Tranform">
<xsl:template match="/">
<html>
<body>
<h2>Pods Papers</h2>
<table border="1">
<tr bgcolor="#9ACD32">
<th>Author</th>
<th>Title</th>
<th>Pages</th>
<th>Year</th>
</tr>
<xsl:for-each select="pods-papers/inproceedings">
<tr>
<td><xsl:value-of select="author"/></td>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="pages"/></td>
<td><xsl:value-of select="year"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
And the podcatalog.xml can be found here
The error I am getting is: "Error loading stylesheet: Parsing an XSLT stylesheet failed."

Change:
<xsl:for-each select="pods-papers/inproceedings key">
to:
<xsl:for-each select="pods-papers/inproceedings">
'key' is an attribute of element

It looks like you’re defining entities the wrong way (<!ENTITY Aring "&#197;" > should have & instead of &) and, more seriously, without a DTD. It appears to be a longstanding request that we should be able to do that, but... So the problem is that your XML file has a DOCTYPE declaration that contains just entity definitions, not a document type definition.
The options appear to be:
Write a DTD. Some work, but might be useful for documentation purposes.
Replace the entity references by the characters themselves or by character references, e.g. Ö by Ö or by Ö.

Related

xsl template is overriding with xsl include

I am trying to create some reusable templates while developing a html page for xml with xsl. But when I include the other xsl's, the main xsl template is getting overridden instead of adding it to it. please suggest.
Here is my xml,
<employee>
<address>
<street>street1</street>
<city>city1</city>
<doornumber>1-23</doornumber>
<pincode>123456</pincode>
</address>
<personalinfo>
<name>testname1</name>
<phone>999999999</phone>
<dob>23-09-34</dob>
</personalinfo>
<remarks>
<education>
<name>testname2</name>
<college>college1</college>
<gpa>7.5</gpa>
</education>
</remarks>
<data>
<name>data1</name>
</data>
<data>
<name>data2</name>
</data>
<data>
<name>data3</name>
</data>
<data>
<name>data4</name>
</data>
<data>
<name>data5</name>
</data>
</employee>
Here is my main xsl,
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:template match="/">
<html>
<body>
<table>
<tr>
<th>Name</th>
<th>College</th>
<th>City</th>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="employee">
<tr>
<td>
<xsl:value-of select="personalinfo/name"/>
</td>
<td>
<xsl:value-of select="remarks/education/college"/>
</td>
<td>
<xsl:value-of select="address/city"/>
</td>
</tr>
</xsl:template>
<!-- <xsl:include href="test_include1.xsl" /> -->
<!-- <xsl:include href="test_include2.xsl" /> -->
</xsl:stylesheet>
Here is my test_include1.xsl,
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:template match="employee">
<table><tr>
<th>data names</th></tr>
<xsl:for-each select="data">
<tr>
<td>
<xsl:value-of select="name"/>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
Here is my test_include2.xsl,
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:template match="employee">
<table><tr>
<th>Name</th>
<th>College</th></tr>
<tr>
<td>
<xsl:value-of select="personalinfo/name"/>
</td>
<td>
<xsl:value-of select="remarks/education/college"/>
</td>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>
I am trying to modularize the same xml data in different templates so that I can reuse the same templates in other stylesheets. Please suggest how I can acheive this. Thank you.
Here is the expected result,
<html><body>
<table>
<tr>
<th>Name</th>
<th>College</th>
<th>City</th>
</tr>
<tr>
<td>testname1</td>
<td>college1</td>
<td>city1</td>
</tr>
</table>
<table>
<tr><th>data names</th></tr>
<tr><td>data1</td></tr>
<tr><td>data2</td></tr>
<tr><td>data3</td></tr>
<tr><td>data4</td></tr>
<tr><td>data5</td></tr>
</table>
<table>
<tr>
<th>Name</th>
<th>College</th>
</tr>
<tr>
<td>testname1</td>
<td>college1</td>
</tr>
</table>
</body></html>
Firstly, I don't see any xsl:include declarations in any of these stylesheets, so I'm not quite sure what you are doing. [Sorry - missed the pale grey commented out code - poor contrast on my monitor.]
Secondly, with XSLT 1.0 the behaviour when you have two templates matching the same node, with the same precedence and priority, is not very well defined. Technically it's an error, but the processor is allowed to recover by choosing the rule that comes "last in the stylesheet" - which itself is not particularly well defined when there are multiple modules involved.
Thirdly, you say "the main xsl template is getting overridden instead of adding it to it". This suggests you have some particular expectation of how you want it to behave, but I can't really work out what this expectation is. You haven't given any expected results, so I don't know what you are trying to achieve. But it will always be the case, if you have more than one rule that matches a node, that you either get an error, or exactly one of the rules is executed - they are never combined in any way.
This could be achieved by modes.
Another way is to give each xsl:template match a priority number. The one which you want to get executed should have the highest priority. Priority is attribute of xsl:template
<xsl:template match = "employee" priority = "4"> do the task </xsl:template>

Add attribute to XML root node using XSLT (and output existing XSLT with HTML?)

I apologize for this somewhat as there are similar questions around, however I've attempted to apply all of those and cannot get mine to work with existing stylesheet html output.
I have an existing XML and an existing XSLT which has HTML markup.
I Simply want use the XSLT to also add an attribute to my XML root node but still also output the XSLT HTML.
How would I do this?
My XML: (I want to add an xmlns attribute to the node: "StockList")
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="do_it.xsl"?>
<StockList>
<StockItem>
<Item>AX123</Item>
<Description>Firetruck</Description>
<Count>500</Count>
<Order>No</Order>
</StockItem>
</StockList>
My XSLT: (do_it.xsl)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:aa="http://www.w3schools.com/MMMXXX">
<xsl:template match="/">
<html>
<body>
<h2>Things On The Shelf:</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th style="text-align:left">Item Code</th>
<th style="text-align:left">Item Description</th>
<th style="text-align:left">Current Count</th>
<th style="text-align:left">On Order?</th>
</tr>
<xsl:for-each select="aa:StockList/aa:StockItem">
<tr>
<td><xsl:value-of select="aa:Item"/></td>
<td><xsl:value-of select="aa:Description"/></td>
<td><xsl:value-of select="aa:Count"/></td>
<td><xsl:value-of select="aa:Order"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
So what do I need to do to my XSLT and WHERE do I need to do it? I've attempted about 15 different 'apply templates' but while I manage to add the attribute I can't also add my html table? :(
Please help.
This has the ring of an XY problem. Just be assured that you cannot change your source document through XSLT, i.e. adding a new attribute to it so your existing stylesheet code could work. You also cannot produce an intermediate document and then transform that through XSLT 1.0 (at least as far as I know).
You have to do one of two things:
Modify whatever is generating the source XML so it correctly declares the namespace of <StockList> for you. You could do this like so:
using (MemoryStream ms = new MemoryStream())
{
dataSet.WriteXml(ms);
ms.Position = 0; // reset!
XDocument xd = XDocument.Load(ms);
XNamespace aa = "http://www.w3schools.com/MMMXXX";
foreach (var el in xd.Root.DescendantsAndSelf())
{
el.Name = aa.GetName(el.Name.LocalName);
}
xd.Root.Add(new XAttribute(XNamespace.Xmlns + "aa", aa);
xd.Save(ms); // or just return the XDocument.ToString(), or return XDocument.CreateReader() as desired
}
Modify your XSLT so that it doesn't care about namespaces. For example, change <xsl:for-each select="aa:StockList/aa:StockItem"> to <xsl:for-each select="*[local-name()='StockList']/*[local-name()='StockItem']"> and so on everywhere you have a select using that namespace prefix. This is probably the easier fix - I'd go with this solution myself.
If you want to apply two transformations in one style sheet with XSLT 1.0 where the first adds the namespace (you would need to add it to all elements) and the second transforms the result of the first to HTML then you need to perform one step with a variable that is a result tree fragment and then convert that result tree fragment to a node set to apply your for-each or other templates. Converting a result tree fragment to a node set can be done with most XSLT processors using the EXSLT extension function exsl:node-set (http://exslt.org/exsl/functions/node-set/index.html), however MSXML used by IE does not support that EXSLT function, only a similar function in a different namespace. Using the ms:script extension element it is however possible to have MSXML support exsl:node-set, so a complete style sheet doing two transformations looks like
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:aa="http://example.com/ns1"
xmlns:exsl="http://exslt.org/common"
xmlns:ms="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="aa exsl ms"
version="1.0">
<ms:script language="JScript" implements-prefix="exsl">
this['node-set'] = function(nodeList) {
return nodeList;
}
</ms:script>
<xsl:variable name="rtf1">
<xsl:apply-templates mode="add-namespace"/>
</xsl:variable>
<xsl:template match="*" mode="add-namespace">
<xsl:element name="aa:{local-name()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates mode="add-namespace"/>
</xsl:element>
</xsl:template>
<xsl:template match="/">
<html>
<body>
<h2>Things On The Shelf:</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th style="text-align:left">Item Code</th>
<th style="text-align:left">Item Description</th>
<th style="text-align:left">Current Count</th>
<th style="text-align:left">On Order?</th>
</tr>
<xsl:for-each select="exsl:node-set($rtf1)/aa:StockList/aa:StockItem">
<tr>
<td><xsl:value-of select="aa:Item"/></td>
<td><xsl:value-of select="aa:Description"/></td>
<td><xsl:value-of select="aa:Count"/></td>
<td><xsl:value-of select="aa:Order"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
The example is online at http://home.arcor.de/martin.honnen/xslt/test2015100701.xml respectively http://home.arcor.de/martin.honnen/xslt/test2015100701.xsl.
Works as intended with current versions of Firefox, Chrome and IE on Windows 10. Unfortunately Microsoft Edge complains about an error in the XSLT, I am not sure what causes this as Edge like IE 11 uses MSXML 6 to do XSLT. To make it work with Edge I rewrote the style sheet not to make use of ms:script and instead use function-available and xsl:when:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:aa="http://example.com/ns1"
xmlns:exsl="http://exslt.org/common"
xmlns:ms="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="aa exsl ms"
version="1.0">
<xsl:variable name="rtf1">
<xsl:apply-templates mode="add-namespace"/>
</xsl:variable>
<xsl:template match="*" mode="add-namespace">
<xsl:element name="aa:{local-name()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates mode="add-namespace"/>
</xsl:element>
</xsl:template>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="function-available('exsl:node-set')">
<xsl:apply-templates select="exsl:node-set($rtf1)/aa:StockList"/>
</xsl:when>
<xsl:when test="function-available('ms:node-set')">
<xsl:apply-templates select="ms:node-set($rtf1)/aa:StockList"/>
</xsl:when>
<xsl:otherwise>
<html>
<body>
<p>Your XSLT processor does not support exsl:node-set or ms:node-set.</p>
</body>
</html>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/aa:StockList">
<html>
<body>
<h2>Things On The Shelf:</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th style="text-align:left">Item Code</th>
<th style="text-align:left">Item Description</th>
<th style="text-align:left">Current Count</th>
<th style="text-align:left">On Order?</th>
</tr>
<xsl:for-each select="aa:StockItem">
<tr>
<td><xsl:value-of select="aa:Item"/></td>
<td><xsl:value-of select="aa:Description"/></td>
<td><xsl:value-of select="aa:Count"/></td>
<td><xsl:value-of select="aa:Order"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
That way of course it works with Firefox, Chrome and IE as well.

Multiple XSL files combination

Hi I have two xsl files and I have one xml how can I combine these xsl files together at transform type and combine them it and get one html
index.html
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE xsl:stylesheet [<!ENTITY nbsp " "><!ENTITY bull "•">]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:include href="hello.xsl"/>
<xsl:template match="/">
<html>
<tr>
<td><xsl:value-of select="name" /></td>
</tr>
</html>
</xsl:template>
</xsl:stylesheet>
and then my send xsl is
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE xsl:stylesheet [<!ENTITY nbsp " "><!ENTITY bull "•">]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<table>
<tr>
<td><xsl:value-of select="age" /></td>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>
and my xml is
<xml>
<name>abc</name>
<age>15</age>
</xml>
What I want output is like
<html>
<tr><td>abc</td></tr>
<table>
<tr><td>15</td></tr>
</table>
</html>
Is that is do able thing to perform in xsl I search so many site but couldn't find answer, plz help
EDIT: You edited your question and are now asking something completely different.
As I said, you can combine templates and other element from separate stylesheets with xsl:include and xsl:import. See the relevant section of the specification here.
There are ways to combine separate stylesheets (e.g. via xsl:include and xsl:import), but in your case I do not think it is even necessary.
Your stylesheets only have one template each and they simply retrieve values from an input XML which is a trivial action. There is really no need to store those two templates in separate stylesheets.
Write one stylesheet that produces both the html element and the table.
Let me emphasize another thing: It is evident in your question that you do not really understand the workings of both XSLT and HTML. To give a few hints:
the output you request is malformed HTML. A tr element cannot be an immediate child of html. Content must be placed inside body, as opposed to header.
both of the templates you show match /. Obviously, it makes no sense to combine them if they match the same node.
Please take the time to study the basics of XSLT and HTML before asking a new question.
Stylesheet
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="html" indent="yes"/>
<xsl:template match="/xml">
<html>
<body>
<table border="solid">
<tr>
<xsl:for-each select="*">
<td>
<xsl:value-of select="name()"/>
</td>
</xsl:for-each>
</tr>
<tr>
<td>
<xsl:value-of select="*[1]"/>
</td>
<td>
<xsl:value-of select="*[2]"/>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Output
<html>
<body>
<table border="solid">
<tr>
<td>name</td>
<td>age</td>
</tr>
<tr>
<td>abc</td>
<td>15</td>
</tr>
</table>
</body>
</html>

How to parse the xml data into html?

Here is my xml:
<Catalog>
<catalogDetail catalogId="DemoCatalog">
<catalogName>Demo Catalog</catalogName>
</catalogDetail>
<catalogDetail catalogId="GoogleCatalog">
<catalogName>Google Catalog</catalogName>
</catalogDetail>
</Catalog>
I want it to be read in HTML file how can I do this???
To do this your HTML file should contain some JavaScript code, so you will want to learn how to parse XML in Javascript.
Here is a good StackOverflow question on this topic: XML parsing in JavaScript
You can do by using PHP's XML Library called simplexml for more information check this link
http://www.w3schools.com/php/php_xml_simplexml.asp
NOTE : If you can elaborate on what technology you're using, I'll try to provide a more complete example.
I would suggest using XSLT for this. With XSLT, you can pass in the XML fragment, parse it, and return formatted HTML.
Here's an example XSLT document that converts XML to HTML:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>Artist</th>
</tr>
<xsl:for-each select="catalog/cd">
<tr>
<td>
<xsl:value-of select="title"/>
</td>
<td>
<xsl:value-of select="artist"/>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Transforming XML into HTML (as opposed to xhtml)

i want to transform some xml into HTML that has the following format:
<TR><TD> col1 <TD> col2 <TD> col3 </TR>
Note: The output is HTML, complete with optional closing tags omitted. This is the problem, and the reason the question exists.
A snippet of the XSL i'm using is:
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
doctype-system='http://www.w3.org/TR/html4/strict.dtd'
doctype-public='-//W3C//DTD HTML 4.01//EN'
indent='yes'
method='html'
/>
...
<xsl:for-each select="/">
<TR><TD><xsl:value-of select="col1"/><TD><xsl:value-of select="col2"/><TD><xsl:value-of select="col3"/></TR>
</xsl:for-each>
You can see that the guts of the XSL matches my desired HTML (wrapped for easy reading):
<TR> <TD><xsl:value-of select="Column1"/>
<TD><xsl:value-of select="Column2"/>
<TD><xsl:value-of select="Column3"/> </TR>
Note: Those of you who know the error i'm getting from the XSLT: hopefully already know the answer.
When presented with my XSL (which, don't forget, is a form of xml), i get the non-well formed error:
End tag 'TR' does not match the start tag 'TD'.
This makes perfect sense. Indeed:
<TD><xsl:value-of select="Column3"/> </TR>
i do not close the TD element before closing the TR. So the question is:
How can i transform xml into HTML, given that HTML is not xml?
See also
HTML: Include, or exclude, optional closing tags?
XSLT: Transforming into non-xml content?
Omitting optional tags of html
Update one
It has been suggested that one could simply include the closing tags anyway, in order to make the XSL validate (shown wrapped for easy reading):
<TR> <TD><xsl:value-of select="col1"/></TD>
<TD><xsl:value-of select="col2"/></TD>
<TD><xsl:value-of select="col3"/></TD> </TR>
then, by using xsl:output method='html', the final HTML content would have the </TD> tags magically omitted. Except it doesn't work:
<TR><TD>col1</TD><TD>col2</TD><TD>col3</TD></TR>
Update two
It has been suggested that i give up, don't bother asking this question, and just include the optional closing tags. That's possible, but that's not my question. Also, the "solution" doesn't work for elements where the closing tag is forbidden, e.g.:
<BR/>
or
<BR></BR>
How would i include a <BR> element in my HTML output, given that it is forbidden in HTML to close a <BR> element.
Here's one way to do this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/*">
<TR><TD><xsl:value-of select="col1"/><TD><xsl:value-of select="col2"/><TD><xsl:value-of select="col3"/></TR>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>
<col1>1</col1>
<col2>2</col2>
<col3>3</col3>
</t>
the wanted result is correctly produced:
<TR><TD>1<TD>2<TD>3</TR>
I believe the simplest thing is to just accept you're going to have closing tags in the output. While they might be optional, I believe most people would agree that best practice is to include them.
Is there a reason you really don't want optional closing tags in the output?
Re Update Two
There's no problem with this update. With method="html" <BR/> will be output as <BR>:
XSLT (note <BR/>):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
doctype-system='http://www.w3.org/TR/html4/strict.dtd'
doctype-public='-//W3C//DTD HTML 4.01//EN'
indent='yes'
method='html'
/>
<xsl:template match="/">
<HTML><BODY>
<TR>
<xsl:apply-templates/>
</TR>
<BR/> <!-- HERE -->
</BODY></HTML>
</xsl:template>
<xsl:template match="item">
<TD><xsl:value-of select="."/></TD>
</xsl:template>
</xsl:stylesheet>
Input:
<root>
<item>one</item>
<item>two</item>
</root>
Output (note <BR>):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<HTML><BODY>
<TR>
<TD>one</TD>
<TD>two</TD>
</TR>
<BR> <!-- HERE -->
</BODY></HTML>
Have you tried the output as "HTML"? Elements that shouldn't be self-closed in HTML are not (i.e. <BR>, <img>).
If you still don't like how the XSLT engine is serializing HTML output, then you could set your <xsl:output method="text"> and construct the "HTML" that you want:
<TR><TD><xsl:value-of select="col1"/><TD><xsl:value-of select="col2"/><TD><xsl:value-of select="col3"/></TR>
which produces:
<TR><TD>col1<TD>col2<TD>col3</TR>
Ian, have you tried <xsl:output method="text">?
http://www.w3schools.com/xsl/el_output.asp