No elements after XSL namespace added - xslt

Any help would be appreciated on this simple (I hope) problem. The xsl:for-each fails to find any elements after adding a namespace to this XML doc:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="cdsort.xsl"?>
<catalog xmlns="http://www.mycompany.com/test" >
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
</cd>
<cd>
<title>Tupelo Honey</title>
<artist>Van Morrison</artist>
</cd>
</catalog>
Here is the XSL code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:vv="http://www.mycompany.com/test"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<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="vv: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>

You've set the default namespace for the whole document so the child elements in the xpaths also need a prefix:
<xsl:for-each select="vv:catalog/vv:cd">
<tr>
<td><xsl:value-of select="vv:title" /></td>
<td><xsl:value-of select="vv:artist" /></td>
</tr>
</xsl:for-each>

Related

Greater than and lesser than condition in xsl

I would like to have greater than and lesser than condition in xsl.
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
<cd>
<title>Hide your heart</title>
<artist>Bonnie Tyler</artist>
<country>UK</country>
<company>CBS Records</company>
<price>9.90</price>
<year>1988</year>
</cd>
</catalog>
xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<xsl:for-each select="catalog/cd">
<tr>
<td>
<xsl:value-of select="title"/>
</td>
<xsl:choose>
<xsl:when test="price > '9' and price < '10'">
<td bgcolor="#B22222">
<xsl:value-of select="artist"/>
</td>
</xsl:when>
</xsl:choose>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
I tried
<xsl:when test="price > 9 and price < 10">.
But is not working.
Expected result: Display records which price is between 9 and 10.
Actual result : Nothing display
I added the xsl namespace, and its working fine.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<xsl:for-each select="catalog/cd[price > '9' and price < '10']">
<tr>
<td>
<xsl:value-of select="title"/>
</td>
<td bgcolor="#B22222">
<xsl:value-of select="artist"/>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Output.
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr>
<td>Hide your heart</td>
<td bgcolor="#B22222">Bonnie Tyler</td>
</tr>
</table>
</body>
</html>
I think are you want following:-
<xsl:template match="catalog/cd">
<xsl:choose>
<xsl:when test="price > 9 and price < 10">
<xsl:copy-of select="*"/>
</xsl:when>
</xsl:choose>
</xsl:template>
OutPut:-
<title>Hide your heart</title>
<artist>Bonnie Tyler</artist>
<country>UK</country>
<company>CBS Records</company>
<price>9.90</price>
<year>1988</year>

XSLT sum grouped table cell

Maybe you can help me.
I don't know how to sum some table's cell "Year" which are grouped by "Title". I need that sum cell also would be merge as first cell "Title".
I used sum(), but it returs 0.
XMl Code:
<?xml version="1.0" encoding="UTF-8"?>
<LIST>
<Row>
<TITLE>Empire Burlesque</TITLE>
<YEAR>2001</YEAR>
<artist>Bob Dylan</artist>
<artist1>Bob Dylan1</artist1>
</Row>
<Row>
<TITLE>Empire Burlesque</TITLE>
<YEAR>2002</YEAR>
<artist>Bob Dylan</artist>
<artist1>Bob Dylanas</artist1>
</Row>
<Row>
<TITLE>Empire Burlesque</TITLE>
<YEAR>2003</YEAR>
<artist>Bonnie Tyler</artist>
<artist1>Bob Dylan</artist1>
</Row>
<Row>
<TITLE>Empire Burlesque</TITLE>
<YEAR>2004</YEAR>
<artist>Bonnie Tyler</artist>
<artist1>Bob Dylanas</artist1>
</Row>
<Row>
<TITLE>Empire Burlesque1</TITLE>
<YEAR>2005</YEAR>
<artist>Bonnie Tyler</artist>
<artist1>Bob Dylan</artist1>
</Row>
<Row>
<TITLE>Empire Burlesque1</TITLE>
<YEAR>2006</YEAR>
<artist>Bonnie Tyler</artist>
<artist1>Bob Dylanas</artist1>
</Row>
</LIST>
XSLT code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:key name="cds" match="Row" use="TITLE" />
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>Year</th>
<th>Artist</th>
<th>Artist1</th>
</tr>
<xsl:for-each select="LIST/Row[generate-id() = generate-id(key('cds', TITLE)[1])]" >
<tr>
<td>
<xsl:if test="key('cds', TITLE)[1]">
<xsl:attribute name="rowspan">
<xsl:value-of select="count(key('cds', TITLE))" />
</xsl:attribute>
</xsl:if>
<xsl:value-of select="TITLE"/>
</td>
<td>
<xsl:value-of select="YEAR"/>
</td>
<td>
<xsl:value-of select="artist"/>
</td>
<td>
<xsl:value-of select="artist1"/>
</td>
</tr>
<xsl:for-each select="key('cds', TITLE)[position() > 1]">
<tr>
<td>
<xsl:value-of select="YEAR"/>
</td>
<td>
<xsl:value-of select="artist"/>
</td>
<td>
<xsl:value-of select="artist1"/>
</td>
</tr>
</xsl:for-each>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Now result is that:
Try sum(key('cds', TITLE)/YEAR) inside of the for-each.

XSLT Correct usage of child::* , Difference between using xsl:for-each and xsl:template in this scenario

I tried creating XSL transformation for the input xml of the below format.
With both <xsl:for-each /> and <xsl:template />
XML 1:
<books>
<book>
<title>charithram</title>
<author>sarika</author>
</book>
<book>
<title>doublebell</title>
<author>psudarsanan</author>
</book>
</books>
XSLT 1:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<table border="1">
<tr>
<th>Title</th>
<th>Author</th>
</tr>
<xsl:for-each select="books/book">
<tr>
<td><xsl:value-of select="title" /></td>
<td><xsl:value-of select="author" /></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Or
XSLT 2:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<table border="1">
<tr>
<th>Title</th>
<th>Author</th>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="books/book">
<tr>
<td><xsl:value-of select="title" /></td>
<td><xsl:value-of select="author" /></td>
</tr>
</xsl:template>
</xsl:stylesheet
......
Now, if the XML is
XML 2:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book.child.1>
<title>charithram</title>
<author>sarika</author>
</book.child.1>
<book.child.2>
<title>doublebell</title>
<author>psudarsanan</author>
</book.child.2>
</books>
I am able to accomplish the result with usage of books/child::*
XSLT 3:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<table border="1">
<tr>
<th>Title</th>
<th>Author</th>
</tr>
<xsl:for-each select="books/child::*">
<tr>
<td><xsl:value-of select="title" /></td>
<td><xsl:value-of select="author" /></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Questions:
What is the difference between using <xsl:for-each/> and applying template in the above scenario? I do not see any difference. [XSLT 1 and XSLT 2]
Please validate if this is the correct usage. [using <xsl:for-each select="books/child::*"> to accomplish the result] [XSLT 3]
Update:
I have removed my third question and will post in a different thread.
1) In fact, you're right. xsl:for-each is a sort of "anonymous inline template". It's actually bad practice in many cases, since it tends to indicate that the stylesheet is being written procedurally rather than rule-driven... but it is occasionally the best way to express your logic. As with most programming languages, there's more than one way to solve most problems and it's up to the programmer to develop a sense of style to pick the best one.
2) As Ian Roberts said, "yes, that will work, but books/child::* can be shortened to books/* as child:: is the default axis". (He does deserve the credit for answering that one -- I was half-asleep and didn't get a Round Tuit.)

Parse through multiple nodes using xslt

Below is my input xml
<Record>
<Header>
<field1/>
</Header>
<Body>
<firstname>x1</firstname>
<lastname>y1</lastname>
<company>Test1</company>
<Body>
<Body>
<firstname>x2</firstname>
<lastname>y2</lastname>
<company></company>
<Body>
<Body>
<firstname>x3</firstname>
<lastname>y3</lastname>
<company>Test2</company>
<Body>
</Record>
I am trying to loop through body and check if the company value is blank,to output the corresponding first name and last name.This whole output,I am mapping to DATA on the target using xslt mapper.Can someone help me with the below code which is not working
<?xml version='1.0' ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="Namespace">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="NAME" select="/RecordSet/Body"/>
<xsl:variable name="break"><br></xsl:variable>
<xsl:variable name="tableB"><table Border="1" BorderColor="#000000" cellpadding="4" cellspacing="0" ></xsl:variable>
<xsl:variable name="tableE"></table></xsl:variable>
<xsl:variable name="trB"><tr></xsl:variable>
<xsl:variable name="trE"></tr></xsl:variable>
<xsl:variable name="tdB"><td></xsl:variable>
<xsl:variable name="tdE"></td></xsl:variable>
<xsl:variable name="nbsp">&nbsp;</xsl:variable>
<xsl:variable name="thB"><tr BGCOLOR="#CCCCCC"></xsl:variable>
<xsl:template match="/">
<DATA>
<xsl:value-of select="$tableB"/>
<xsl:value-of select="$thB"/>
<xsl:value-of select="$tdB"/><B>FirstName</B>
<xsl:value-of select="$nbsp"/>
<xsl:value-of select="$tdE"/>
<xsl:value-of select="$tdB"/><B>LASTNAME </B>
<xsl:value-of select="$nbsp"/>
<xsl:value-of select="$tdE"/>
<xsl:value-of select="$trE"/>
<xsl:value-of select="$trB"/>
<xsl:for-each select="$NAME/Body[string-length(company) > 0]">
<xsl:value-of select="$tdB"/>
<xsl:value-of select="$MT_NAME/firstname"/>
<xsl:value-of select="$nbsp"/>
<xsl:value-of select="$tdE"/>
<xsl:value-of select="$tdB"/>
<xsl:value-of select="$MT_NAME/lastname"/>
<xsl:value-of select="$nbsp"/>
<xsl:value-of select="$tdE"/>
<xsl:if test="position() mod 2 = 0">
<xsl:value-of select="$trE"/>
</xsl:if>
</xsl:for-each>
<xsl:value-of select="$tableE"/>
</DATA>
The output should be
|FIRSTNAME|LASTNAME|
| X2 | Y2 |
The provided code doesn't produce HTML at all -- it produces strings -- one-dimensional text.
Also, AFAIK, DATA isn't an HTML element.
Also, the provided "XML" is severely malformed.
Here is an example how to produce an HTML table with XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<table>
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Company</td>
</tr>
</thead>
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="Body">
<tr>
<xsl:apply-templates select="*"/>
</tr>
</xsl:template>
<xsl:template match="Body/*">
<td> </td>
</xsl:template>
<xsl:template match="Body/*[normalize-space()]">
<td><xsl:value-of select="."/></td>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document (the provided severely malformed text -- corrected):
<Record>
<Header>
<field1/>
<Body>
<firstname>x1</firstname>
<lastname>y1</lastname>
<company>Test1</company>
</Body>
<Body>
<firstname>x2</firstname>
<lastname>y2</lastname>
<company></company>
</Body>
<Body>
<firstname>x3</firstname>
<lastname>y3</lastname>
<company>Test2</company>
</Body>
</Header>
</Record>
A meaningful and sensible HTML table is produced:
<table>
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Company</td>
</tr>
</thead>
<tr>
<td>x1</td>
<td>y1</td>
<td>Test1</td>
</tr>
<tr>
<td>x2</td>
<td>y2</td>
<td> </td>
</tr>
<tr>
<td>x3</td>
<td>y3</td>
<td>Test2</td>
</tr>
</table>
I have to take a guess at your requirements as they are not very well explained.
This XSLT 1.0 style-sheet...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="/">
<DATA>
<table Border="1" BorderColor="#000000" cellpadding="4" cellspacing="0">
<tr BGCOLOR="#CCCCCC">
<th>First name</th>
<th>Last name</th>
<th>Company</th>
</tr>
<xsl:apply-templates select="*/Body" />
</table>
</DATA>
</xsl:template>
<xsl:template match="Body">
<tr>
<td><xsl:value-of select="firstname" /></td>
<td><xsl:value-of select="lastname" /></td>
<td>
<xsl:choose>
<xsl:when test="company!=''" >
<xsl:value-of select="company" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(firstname,' ',lastname)" />
</xsl:otherwise>
</xsl:choose>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
... when applied on this document...
<Record>
<Header>
<field1/>
</Header>
<Body>
<firstname>x1</firstname>
<lastname>y1</lastname>
<company>Test1</company>
</Body>
<Body>
<firstname>x2</firstname>
<lastname>y2</lastname>
<company/>
</Body>
<Body>
<firstname>x3</firstname>
<lastname>y3</lastname>
<company>Test2</company>
</Body>
</Record>
...will yield...
<DATA>
<table Border="1" BorderColor="#000000" cellpadding="4" cellspacing="0">
<tr BGCOLOR="#CCCCCC">
<th>First name</th>
<th>Last name</th>
<th>Company</th>
</tr>
<tr>
<td>x1</td>
<td>y1</td>
<td>Test1</td>
</tr>
<tr>
<td>x2</td>
<td>y2</td>
<td>x2 y2</td>
</tr>
<tr>
<td>x3</td>
<td>y3</td>
<td>Test2</td>
</tr>
</table>
</DATA>
Note
Notice that the middle record has a cell value of 'x2 y2' for Company as per stated requirements when the input Company is empty or missing.
Update
The input document is still badly malformed. In consideration of the OP's updated requirements, this XSLT 1.0 style-sheet...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="/">
<DATA>
<table Border="1" BorderColor="#000000" cellpadding="4" cellspacing="0">
<tr BGCOLOR="#CCCCCC">
<th>First name</th>
<th>Last name</th>
</tr>
<xsl:apply-templates select="*/Body[company='']" />
</table>
</DATA>
</xsl:template>
<xsl:template match="Body">
<tr>
<td><xsl:value-of select="firstname" /></td>
<td><xsl:value-of select="lastname" /></td>
</tr>
</xsl:template>
</xsl:stylesheet>
...when applied to the same input document as before, yields...
<DATA>
<table Border="1" BorderColor="#000000" cellpadding="4" cellspacing="0">
<tr BGCOLOR="#CCCCCC">
<th>First name</th>
<th>Last name</th>
</tr>
<tr>
<td>x2</td>
<td>y2</td>
</tr>
</table>
</DATA>

XSLT Retrieving Attribute Info to Display in table

Hi I'm new to XSLT and I'm trying to display the value of a parent node along with the values of my data.
I have this XML..
<?xml-stylesheet type="text/xsl" href="Sample.xsl"?>
<DataView Client="Client1" ID="1000" TimeStamp="12/7/2011 5:35:09 PM">
<Group ID="5000" Name="GroupName1">
<SubGroup ID="7000" Order="0" Name="NameIWant1">
<Data ID="1" Name="DataName1" Order="0">1</Data>
<Data ID="2" Name="DataName2" Order="0">2</Data>
<Data ID="3" Name="DataName3" Order="0">3</Data>
<Data ID="12" Name="DataName4" Order="0">4</Data>
</SubGroup>
<SubGroup ID="8000" Order="0" Name="NameIWant2">
<Data ID="1" Name="DataName1" Order="0">6</Data>
<Data ID="2" Name="DataName2" Order="0">7</Data>
<Data ID="3" Name="DataName3" Order="0">8</Data>
<Data ID="12" Name="DataName4" Order="0">9</Data>
</SubGroup>
</Group>
</DataView>
Ive written the basic XSL to walk the values
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>My Data</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>DataName1</th>
<th>DataName2</th>
<th>DataName3</th>
<th>DataName4</th>
</tr>
<xsl:for-each select="DataView/Group/SubGroup">
<tr>
<xsl:for-each select="Data">
<td><xsl:value-of select="."/></td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
How do I retrieve and display the attribute value of Subgroup "Name" so my table looks like this...
MyData
NameIWant1 1 2 3 4
NameIWant2 6 7 8 9
Any help is very much appreciated!!
The simple, short answer is to add the following just before the inner for-each loop:
<td><xsl:value-of select="#Name"/></td>
You're already in the context of a DataView/Group/SubGroup node, so you just need to use the attribute axis specifier (#) to select one of its attributes by name.
However, (as usual) I think this is better expressed using individual templates. The for-each loop is almost never necessary in XSLT. The following stylesheet produces the desired result:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<html>
<body>
<h2>My Data</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Subgroup</th>
<th>DataName1</th>
<th>DataName2</th>
<th>DataName3</th>
<th>DataName4</th>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="SubGroup">
<tr>
<td><xsl:value-of select="#Name"/></td>
<xsl:apply-templates/>
</tr>
</xsl:template>
<xsl:template match="Data">
<td><xsl:apply-templates/></td>
</xsl:template>
</xsl:stylesheet>
Output:
<html>
<body>
<h2>My Data</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Subgroup</th>
<th>DataName1</th>
<th>DataName2</th>
<th>DataName3</th>
<th>DataName4</th>
</tr>
<tr>
<td>NameIWant1</td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td>NameIWant2</td>
<td>6</td>
<td>7</td>
<td>8</td>
<td>9</td>
</tr>
</table>
</body>
</html>
<table border="1">
<thead>
<tr bgcolor="#9acd32">
<th>SubGroupName</th>
<th>DataName1</th>
<th>DataName2</th>
<th>DataName3</th>
<th>DataName4</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="DataView/Group/SubGroup">
<tr>
<td>
<xsl:value-of select="#Name"/>
</td>
<xsl:for-each select="Data">
<td><xsl:value-of select="."/></td>
</xsl:for-each>
</tr>
</xsl:for-each>
</tbody>
</table>