i need yout help. I'm struggle with XSLT: I have for example an XML file like this:
<Adresses>
<Person id="1">
<Name>Bott</Name>
<Vorname>Nils</Vorname>
</Person>
<Person id="2">
<Name>Hubert</Name>
<Vorname>Hubertus</Vorname>
</Person>
<Person id="3">
<Name>Large</Name>
<Vorname>Lars</Vorname>
</Person>
<Numbers>
<number>
<id>1</id>
<tel>12354</tel>
</number>
<number>
<id>3</id>
<tel>32354</tel>
</number>
<number>
<id>2</id>
<tel>22354</tel>
</number>
</Numbers>
</Adresses>
And i have to transform to a order HTML Table.
The HTML Table should look like folowwing (Ordering after ID):
<table>
<tr>
<th>Name</th>
<th>Vorname</th>
<th>Tel</th>
</tr>
<tr>
<th>Bott</th>
<th>Nils</th>
<th>12354</th>
</tr>
</table>
My Problem is i don't know how to ckeck: Choose the number where Peron.id = number.id .... It would be realy great if someone could give me a full example for this problem. At web search it is always not so complicated in the tutorials ;-( .... I'm learning XSLT and just know some rules like apply-templates match="Person" .... but how is it possible in such a statement to call a other template wich select the coorect number?
I try to start with that:
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="Adresses/Person">
<xsl:call-template name="curPos">
</xsl:call-template>
<xsl:value-of select="Name"/>
<xsl:value-of select="Vorname"/>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template name="curPos" match="Person">
<xsl:value-of select="position()"/><br> </br>
</xsl:template>
My Problem is i don't know how to ckeck: Choose the number where
Peron.id = number.id ....
That's exactly what keys are for:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="num" match="number" use="id" />
<xsl:template match="/Adresses">
<html>
<body>
<table>
<tr>
<th>Name</th>
<th>Vorname</th>
<th>Tel</th>
</tr>
<xsl:for-each select="Person">
<tr>
<td>
<xsl:value-of select="Name"/>
</td>
<td>
<xsl:value-of select="Vorname"/>
</td>
<td>
<xsl:value-of select="key('num', #id)/tel"/>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Note that your table structure assumes each person has only one phone number (as in your example). However, the XML structure suggests there is a one-to-many relationship between persons and phone numbers, so you might want to consider changing:
<td>
<xsl:value-of select="key('num', #id)/tel"/>
</td>
to:
<td>
<xsl:for-each select="key('num', #id)">
<xsl:value-of select="tel"/>
<br/>
</xsl:for-each>
</td>
I have got the following XSLT 2.0 solution for you:
<xsl:template name="makeTable">
<table>
<tr>
<th>Name</th>
<th>Vorname</th>
<th>Tel</th>
</tr>
<xsl:for-each select="/Adresses/Person">
<tr>
<td><xsl:value-of select="Name"/></td>
<td><xsl:value-of select="Vorname"/></td>
<td><xsl:value-of select="../Numbers/number[id = current()/#id]/tel"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
Now, for the explanation as far as I understand the problem you have is finding the correct XPath expression for selecting the correct telephone number. The most important code snipped in this case is this line:
<td>
<xsl:value-of select="../Numbers/number[id = current()/#id]/tel"/>
</td>
In XSLT 2.0 - I'm not sure about XSLT 1.0 - you can refer to the current loop element with the current() function in an XPath.
To select the telephone number I filter for the number on the condition of its id being equal to the current loop elements attribute id and then getting this node's child tel to get the actual number.
Related
Im new to XSLT and My XML is below
<Aus>
<au>
<ele>
<auid>Au1</auid>
<cid>C1</cid>
<fn>F1</fn>
<sn>S1</sn>
<dept>D1</dept>
</ele>
<ele>
<auid>Au2</auid>
<cid>C2</cid>
<fn>F2</fn>
<sn>S2</sn>
<dept>D2</dept>
</ele>
<ele>
<auid>Au3</auid>
<cid>C3</cid>
<fn>F3</fn>
<sn>S3</sn>
<dept>D4</dept>
</ele>..............
</au>
</Aus>
I want the output like below in html view using XSLT conversion
but XSLT code should be simple to identify next columns by position increment. Please help me.
My current code is
<xsl:for-each select="//Aus/au">
<table>
<tr>
<td><xsl:value-of select="ele[1]/auid"/></td><td><xsl:value-of select="ele[2]/auid"/></td><td><xsl:value-of select="ele[3]/auid"/></td>
</tr>
<tr>
<td><xsl:value-of select="ele[1]/cid"/></td><td><xsl:value-of select="ele[2]/cid"/></td><td><xsl:value-of select="ele[3]/cid"/></td>
</tr>
..........
</table>
</xsl:for-each>
I would do it like this:
<xsl:template match="Aus/au">
<table>
<tbody>
<xsl:apply-templates select="ele[1]/*" mode="row"/>
</tbody>
</table>
</xsl:template>
<xsl:template match="ele/*" mode="row">
<tr>
<xsl:variable name="pos" select="position()"/>
<xsl:apply-templates select="../../ele/*[$pos]"/>
</tr>
</xsl:template>
<xsl:template match="ele/*">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
https://xsltfiddle.liberty-development.net/gVhEaiK
The sample you linked in your comment seems to have more complex input data as it seems there are nested elements, also there seem to be lots of elements without data; however, the templates could be adapted to e.g.
<xsl:template match="authorDetails/authors">
<table>
<tbody>
<xsl:apply-templates
select="element[1]/descendant::*[not(*)]" mode="row"/>
</tbody>
</table>
</xsl:template>
<xsl:template match="element//*" mode="row">
<tr>
<th>
<xsl:value-of select="local-name()"/>
</th>
<xsl:variable name="pos" select="position()"/>
<xsl:apply-templates select="ancestor::authors/element/descendant::*[not(*)][$pos]"/>
</tr>
</xsl:template>
<xsl:template match="element//*">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
Example: https://xsltfiddle.liberty-development.net/gVhEaiK/5
I need to perform a cyclical sequence within another public secuanci and get the data of each person and each status, the problem that I have with the code is that it does not iterate the data that I am delivering. I need help in the second for-each when I have empty fields and then I can work with Word content controls
XML file
<?xml version="1.0"?>
<emailList>
<person>
<name>name 1</name>
<email>g#gmail.com</email>
<status>
<active>1</active>
<active>2</active>
<active>3</active>
</status>
</person>
<person>
<name>name 2</name>
<email>n#hotmail.com</email>
<status>
<active>4</active>
<active>5</active>
</status>
</person>
</emailList>
XSL file
<xsl:stylesheet version="1.0">
<html xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xsl:version="1.0">
<head>
<title>Email Listing</title>
</head>
<body>
<table>
<tr>
<th>Name</th>
<th>E-mail Address</th>
<th>Status</th>
</tr>
<xsl:for-each select="emailList/person">
<tr>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="email"/></td>
<td>
<xsl:for-each select="emailList/person/status">
<xsl:value-of select="active"/>
</xsl:for-each>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
You inner xsl:for-each will be relative to the outer one, which is selecting person.
Try changing it to this...
<xsl:for-each select="status/active">
<xsl:value-of select="."/>
</xsl:for-each>
Where . selects the current node.
If you wanted to separate the values by commas, you could do this....
<xsl:for-each select="status/active">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
Better still, upgrade to XSLT 2.0 and do away with this xsl:for-each entirely..
<td>
<xsl:value-of select="status/active" separator="," />
</td>
<xsl:template match="/">
<html>
<head>
<title>Email Listing</title>
</head>
<body>
<table>
<tr>
<th>Name</th>
<th>E-mail Address</th>
<th>Status</th>
</tr>
<xsl:for-each select="emailList/person">
<tr>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="email"/></td>
<td>
<xsl:for-each select="status">
<xsl:value-of select="active"/>
</xsl:for-each>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
I am a newcomer to XML/XSLT and, so far, in searching SO and the W3SChools sites for clever stuff on Meunchian grouping I haven't been able to grasp an effective solution to my challenge.
Essentially I have one large XML file exported from a database (which means I can't directly edit the XML) which contains invoicing information.
I want to utilise XSLT (1.0) to apply a transformation of the XML into HTML (I am using Saxon) so that each invoice is displayed as a table. However, in the XML, there are many product lines which relate to the same invoice (denoted by the <invoiceNum> element as the identifier).
I don't want to have to create & display a new table for each product line which is part of the same invoice. In my current XSL file, I am trying to create a table for the first instance of a duplicated <invoiceNum> element, and then add only the unique elements from successive product lines (<ProductID>, <ProductName>, <ProductDescription> etc.) and leave out the duplicated shipping information.
In the XML code snippet, you can see the layout of the XML. In the XSL snippet, I hope you can see how I am trying to construct the table. For each successive <invoices_snet> instance in the XML file, I want to add just the product information to the table through the transformation. Using for-each on the <invoices_snet> element simply creates a new table each time.
Should I use conditional logic here, compare the equality of the value of the <invoices_snet> element, use templates?
Your help is much appreciated!
<database>
<invoices>
<invoices_snet>
<invoiceNum NAME="invoiceNum" TYPE="SMALLINT">368</invoiceNum>
<ProductID NAME="ProductID" TYPE="VARCHAR">SS106</ProductID>
<ProductName NAME="ProductName" TYPE="VARCHAR">Senna Sunglasses</ProductName>
<ProductDescription NAME="ProductDescription" TYPE="VARCHAR">Lively sunglasses</ProductDescription>
<Quantity NAME="Quantity" TYPE="SMALLINT">34</Quantity>
<UnitPrice NAME="UnitPrice" TYPE="CURRENCY">40.0000</UnitPrice>
<ExtendedPrice NAME="ExtendedPrice" TYPE="CURRENCY">1360.0000</ExtendedPrice>
<contactName NAME="contactName" TYPE="VARCHAR">Jeff</contactName>
<shippingStreet NAME="shippingStreet" TYPE="VARCHAR">11 Acacia Avenue</shippingStreet>
<shippingCity NAME="shippingCity" TYPE="VARCHAR">Huddersfield</shippingCity>
<shippingCounty NAME="shippingCounty" TYPE="VARCHAR">Yorkshire</shippingCounty>
<shippingPostcode NAME="shippingPostcode" TYPE="VARCHAR">YO12 8LA</shippingPostcode>
<saleDate NAME="salesDate" TYPE="DATETIME">30. Mar. 16</saleDate>
</invoices_snet>
<invoices_snet>
<invoiceNum NAME="invoiceNum" TYPE="SMALLINT">368</invoiceNum>
<ProductID NAME="ProductID" TYPE="VARCHAR">SS368</ProductID>
<ProductName NAME="ProductName" TYPE="VARCHAR">Senna T-shirts</ProductName>
<ProductDescription NAME="ProductDescription" TYPE="VARCHAR">T-shirts of beige colour with cream piping</ProductDescription>
<Quantity NAME="Quantity" TYPE="SMALLINT">20</Quantity>
<UnitPrice NAME="UnitPrice" TYPE="CURRENCY">15.00</UnitPrice>
<ExtendedPrice NAME="ExtendedPrice" TYPE="CURRENCY">300.00</ExtendedPrice>
<contactName NAME="contactName" TYPE="VARCHAR">Jeff</contactName>
<shippingStreet NAME="shippingStreet" TYPE="VARCHAR">11 Acacia Avenue</shippingStreet>
<shippingCity NAME="shippingCity" TYPE="VARCHAR">Huddersfield</shippingCity>
<shippingCounty NAME="shippingCounty" TYPE="VARCHAR">Yorkshire</shippingCounty>
<shippingPostcode NAME="shippingPostcode" TYPE="VARCHAR">YO12 8LA</shippingPostcode>
<saleDate NAME="salesDate" TYPE="DATETIME">30. Mar. 16</saleDate>
</invoices_snet>
</invoices>
</database>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/database">
<html>
<head>
<title>Invoice</title>
<link rel="stylesheet" href="invoicingCSS.css"/>
</head>
<body>
<h1>Invoice</h1>
<br></br>
<xsl:for-each select="invoices/invoices_snet">
<h2>Order for Invoice Number: <xsl:value-of select="invoiceNum"/> </h2>
<table>
<tr>
<th>Product ID</th>
<th>Product Name</th>
<th>Product Description</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Extended Price</th>
<th>Contact Name</th>
<th>Shipping Address</th>
<th>Sales Date</th>
</tr>
<tr>
<td>
<xsl:value-of select="ProductID"/>
</td>
<td>
<xsl:value-of select="ProductName"/>
</td>
<td>
<xsl:value-of select="ProductDescription"/>
</td>
<td>
<xsl:value-of select="Quantity"/>
</td>
<td>
<xsl:value-of select="UnitPrice"/>
</td>
<td>
<xsl:value-of select="ExtendedPrice"/>
</td>
<td>
<xsl:value-of select="contactName"/>
</td>
<td>
<xsl:value-of select="concat(
shippingStreet,' ',
shippingCity,', ',
shippingCounty,', ',
shippingPostcode)"
/>
</td>
<td>
<xsl:value-of select="saleDate"/>
</td>
</tr>
</table>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Grouping is much easier to do in XSLT 2.0, with its built-in xsl:for-each-group instruction.
Try this as your starting point:
XSLT 2.0
<xsl:stylesheet version="2.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:variable name="theader">
<tr>
<th>ProductID</th>
<th>Quantity</th>
<!-- add more as required -->
</tr>
</xsl:variable>
<xsl:template match="/database">
<html>
<xsl:for-each-group select="invoices/invoices_snet" group-by="invoiceNum">
<table border="1">
<xsl:copy-of select="$theader"/>
<xsl:apply-templates select="current-group()"/>
</table>
</xsl:for-each-group>
</html>
</xsl:template>
<xsl:template match="invoices_snet">
<tr>
<td>
<xsl:value-of select="ProductID"/>
</td>
<td>
<xsl:value-of select="Quantity"/>
</td>
<!-- add more as required -->
</tr>
</xsl:template>
</xsl:stylesheet>
<xsl:template match="invoices_snet">
<tr>
<td>
<xsl:value-of select="ProductID"/>
</td>
<td>
<xsl:value-of select="Quantity"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
First do you self a favor and have a look for xslt grouping for XSLT 1.0 this will be muenchian grouping e.g. this
And here the basic structure for a adaption to your xml:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:key name="kinvoices_snet" match="invoices_snet" use="invoiceNum"/>
<xsl:template match="invoices">
<xsl:for-each select="invoices_snet [
count ( key('kinvoices_snet',./invoiceNum)[1] | . ) = 1 ]">
<xsl:variable name="this" select="." />
<g>
<gh>
<xsl:value-of select="invoiceNum" />
</gh>
<!-- group stuff -->
<xsl:for-each select=" key('kinvoices_snet',$this/invoiceNum)">
<!-- group member stuff -->
<gm>
<xsl:value-of select="ProductID" />
</gm>
</xsl:for-each>
</g>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I have following xml document:
...
<x>
<symptom><descr></descr></symptom>
<cause></cause>
<solution></solution>
<cause></cause>
<solution></solution>
</x>
...
In my document I have several <x>
In each <x> I have only one <symptom> and n <cause> and <solution> whereby the amount of <cause> and <solution> is always the same.
I want to get following autmatically generated structure:
<table>
<tr>
<td rowspan=count(cause)><xsl:value-of select="symptom/descr"></td>
<td><xsl:value-of select="cause"></td>
<td><xsl:value-of select="symptom"></td>
<tr>
<tr>
<td><xsl:value-of select="cause"></td>
<td><xsl:value-of select="symptom"></td>
<tr>
...
</table>
I tried following code, which I know is totally wrong. But I'm stuck since several hours and couldn't find any good solution on the internet.
<xsl:for-each select="cause">
<tr>
<td rowspan="count(.)">
<xsl:value-of select="../descr[1]"/>
</td>
<td>
<xsl:value-of select="."/>
</td>
<xsl:for-each select="../solution">
<td>
<xsl:value-of select="."/>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
You're on the right lines with one tr per cause, how about this:
<xsl:template match="x">
<table>
<xsl:for-each select="cause">
<!-- the index of this cause within the list of causes in the current x -->
<xsl:variable name="pos" select="position()" />
<tr>
<!-- first cause - create the spanning symptom cell -->
<xsl:if test="$pos = 1">
<td rowspan="{last()}"><xsl:value-of select="../symptom/descr"/></td>
</xsl:if>
<!-- this cause -->
<td><xsl:value-of select="." /></td>
<!-- the matching solution -->
<td><xsl:value-of select="../solution[$pos]" /></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
A trick here is the last() function, which returns the total number of nodes that the current for-each (or apply-templates) is processing, which in this case is precisely the number of rows you want to span.
This is based on the assumption that you want as result a table with following structure: Given an example input XML
<x>
<symptom>
<descr>
Description
</descr>
</symptom>
<cause>
Cause 1
</cause>
<solution>
Solution 1
</solution>
<cause>
Cause 2
</cause>
<solution>
Solution 2
</solution>
</x>
I assume you want following table:
<table>
<tr>
<td rowspan="2">Description</td>
<td>Cause 1</td>
<td>Solution 1</td>
</tr>
<tr>
<td>Cause 2</td>
<td>Solution 2</td>
</tr>
</table>
This could be done with following XSLT:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="x">
<table>
<xsl:for-each select="cause">
<xsl:apply-templates select="." mode="row">
<xsl:with-param name="amount" select="count(../cause)"/>
<xsl:with-param name="position" select="position()"/>
</xsl:apply-templates>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template match="cause" mode="row">
<xsl:param name="amount"/>
<xsl:param name="position"/>
<tr>
<xsl:if test="$position = 1">
<td rowspan="{$amount}">
<xsl:value-of select="//symptom/descr"/>
</td>
</xsl:if>
<td>
<xsl:value-of select="."/>
</td>
<td>
<xsl:value-of select="following-sibling::solution"/>
</td>
</tr>
</xsl:template>
</xsl:transform>
For each cause a row is created by applying the template
<xsl:template match="cause" mode="row">
with the amount of rows and the the position of the current cause as parameters. If the position is 1, the description is written as value in a td with the amount of cause as value of rowspan.
Each row contains the value of the current cause:
<td>
<xsl:value-of select="."/>
</td>
and the value of the solution at the same position (the solution which is the following-sibling of the current cause):
<td>
<xsl:value-of select="following-sibling::solution"/>
</td>
This is my test XML in this XML i have child element: INSTRUMENT and sub child element: INSTRUMENT/issuer and could be so on ...
5002199
10001
686184SE3
<INSTRUMENT>
<type>FI</type>
<issuer>
<FICode>123456</FICode>
<name>Test</name>
<city>SF</city>
<state>CA</state>
</issuer>
<issueDate>2011-06-22-05:00</issueDate>
<maturityDate>2016-06-22-05:00</maturityDate>
<firstCouponDate>2011-07-22-05:00</firstCouponDate>
<lastCouponDate>2016-05-22-05:00</lastCouponDate>
<couponRate>2.0</couponRate>
<paymentFrequency>12</paymentFrequency>
<callSchedule>
<notice>15</notice>
<timing>0</timing>
<call id="1">
<startDate>2011-12-22-05:00</startDate>
<type>2</type>
<freq>M</freq>
</call>
</callSchedule>
</INSTRUMENT>
<Commision>7.0</Commision>
<price>100.0</price>
I want to display this data in HTML tabular form, and run time the xml element could be any thing, so i can't hard code the element or subelement name
i was trying follwinf XSL
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="*">
<table border="1" width="1000">
<tr>
<td class="section_head">Key</td>
<td class="section_head">Value</td>
</tr>
<xsl:for-each select="*" >
<tr>
<td>
<xsl:value-of select="name(.)" />
</td>
<td>
<xsl:value-of select="." />
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
the HTM Child INSTRUMENT and issuer and callSchedule is comming in tabular form
is there any way i can iterate XSL recursivley to create HTML child table for XML child elements ?
Key
Value
ID
5002199
Code
10001
cusip
686184SE3
INSTRUMENT
FI 123456 Test SF CA 2011-06-22-05:00 2016-06-22-05:00 2011-07-22-05:00 2016-05-22-05:00 2.0 12 15 0 2011-12-22-05:00 100.0 2 M 2012-01-22-05:00 100.0 2012-02-22-05:00 100
Commision
7.0
price
100.0
alloc
100
I am not exactly sure what you are after here. It looks like you want to convert the nodes into name/value pairs and nest the html tables according to the XML hierarchy. Here is a bit of recursion that addresses the problem of not knowing the node names at runtime. Hopefully it well help you get started with this. If it is not what you are looking for you can use it to clarify your question:
<?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" indent="yes"/>
<xsl:template match="/">
<html>
<table>
<xsl:apply-templates/>
</table>
</html>
</xsl:template>
<xsl:template match="*[count(*) = 0]">
<tr>
<td>
<xsl:value-of select="name(.)" />
</td>
<td>
<xsl:value-of select="." />
</td>
</tr>
</xsl:template>
<xsl:template match="*[count(*) > 0]">
<tr>
<td>
<xsl:value-of select="name(.)" />
</td>
<td>
<table>
<xsl:apply-templates/>
</table>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>