Xml to XSLT: getting attributes value and so on - html

I have this xml file:
<?xml version="1.0" encoding="UTF-8"?>
<interface id="RESTInterface">
.....
<abstract_method name="authenticateUser">
<access>public</access>
<parameters>
<argument type="String">account</argument>
<argument type="String">password</argument>
</parameters>
<throws>
<exception>RemoteException</exception>
<exception>SecurityException</exception>
</throws>
<return>boolean</return>
</abstract_method>
<abstract_method name="verifyUser">
<access>public</access>
<parameters>
<argument type="aURL">link</argument>
</parameters>
<return>void</return>
</abstract_method>
</interface>
And I am trying to create an xslt style sheet to create this result:

You could start with smth like this. (I made the assumption that you might be restricted to XSLT 1.0)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" doctype-public="-//W3C//DTD HTML 4.0 Transitional//EN" doctype-system="_http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="interface"></xsl:apply-templates>
</body>
</html>
</xsl:template>
<xsl:template match="interface">
<h1><xsl:value-of select="#id"/></h1>
<table>
<thead>
<tr>
<td>Operation</td>
<td>Argument(s)</td>
<td>Return</td>
<td>Exception</td>
</tr>
</thead>
<xsl:apply-templates select="abstract_method"></xsl:apply-templates>
</table>
</xsl:template>
<xsl:template match="abstract_method">
<tr>
<td><xsl:value-of select="#name"/></td>
<td><p><xsl:apply-templates select="./parameters/argument"></xsl:apply-templates></p></td>
<td><p><xsl:value-of select="./return/text()"/></p></td>
<td><p><xsl:choose>
<xsl:when test="count(./throws/exception) > 0">Yes</xsl:when>
<xsl:otherwise>No</xsl:otherwise>
</xsl:choose></p></td>
</tr>
</xsl:template>
<xsl:template match="argument">
<span><xsl:value-of select="./text()"/>: <xsl:value-of select="#type"/>
<xsl:if test="following-sibling::argument">, </xsl:if></span>
</xsl:template>
</xsl:stylesheet>

Related

Output multiple elements as a JSON array in XSLT

I have an XSL Code as shown below.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />
<xsl:variable name="inlineAddressArray">
<addrline>Home1</addrline>
<addrline>Home2</addrline>
<addrline>Home3</addrline>
</xsl:variable>
<xsl:variable xmlns:exsl="http://exslt.org/common" name="data" select="exsl:node-set($inlineAddreddArray)" />
<addressLines>
<xsl:value-of select="$data/addrline" />
</addressLines>
</xsl:stylesheet>
My expected JSON output should be:
"addressLines":"[Home1,Home2,Home3]"
Output that I'm getting
"addressLines": "Home1Home2Home3"
Basically it is just concatenating every element as a single element.
But, I should get three elements separately as shown above.
Can anyone please help me on this? Don't mind if it's a silly query. I'm very new to XSLT :)
No need for Newtonsoft.Json.JsonConvert.SerializeXmlNode() .
Given this xml:
<inlineAddressArray>
<addrline>Home1</addrline>
<addrline>Home2</addrline>
<addrline>Home3</addrline>
</inlineAddressArray>
Using this xslt 2.0:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="inlineAddressArray">
<xsl:text>"addressLines":"[</xsl:text>
<xsl:value-of select="addrline" separator=","/>
<xsl:text>]"</xsl:text>
</xsl:template>
</xsl:stylesheet>
or using xslt 1.0
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="inlineAddressArray">
<xsl:text>"addressLines":"[</xsl:text>
<xsl:apply-templates select="addrline"/>
<xsl:text>]"</xsl:text>
</xsl:template>
<xsl:template match="addrline">
<xsl:value-of select="."/>
<xsl:if test="not(position()=last())">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
results in this :
"addressLines":"[Home1,Home2,Home3]"
UPDATE
if you also want to deal with empty addrline like i.e.
<inlineAddressArray>
<addrline>Home1</addrline>
<addrline>Home2</addrline>
<addrline></addrline>
</inlineAddressArray>
Your xslt 1.0 could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="inlineAddressArray">
<xsl:text>"addressLines":"[</xsl:text>
<xsl:apply-templates select="addrline"/>
<xsl:text>]"</xsl:text>
</xsl:template>
<xsl:template match="addrline">
<xsl:value-of select="."/>
<xsl:if test=" following-sibling::addrline[(normalize-space(.))]">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="addrline[not(normalize-space(.))]"/>
</xsl:stylesheet>

XSLT How to check if XML Node exists?

I have XML file:
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<Data>
<Records>
<Record>
<AddInfo>
<Info>
</Info>
</AddInfo>
</Record>
</Records>
</Data>
and XSL file:
<?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="Dane">
<html>
<link rel="stylesheet" type="text/css" href="report.css"></link>
<body>
<h2>Table1</h2>
<table border="1" cellspacing="0">
<tr>
<th>XXX</th>
</tr>
<xsl:for-each select="Records/Record">
<tr>
<td>
<xsl:value-of select="XXX"/>
</td>
</tr>
</xsl:for-each>
</table>
<h2>SecondTable</h2>
<table border="1" cellspacing="0">
<tr>
<th>YYY</th>
<th>ZZZ</th>
</tr>
<xsl:for-each select="Records/Record/AddInfo/Info">
<tr>
<td>
<xsl:value-of select="YYY"/>
</td>
<td>
<xsl:value-of select="ZZZ"/>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
And I want to make it like this: if node exists, display table with "Info" nodes, and if not, display SOME TEXT.
I've been trying
<xsl:if test="following-sibling::AddInfo">
</xsl:if>
and
<xsl:if test="AddInfo">
</xsl:if>
But it is not working.
I want it like this:
Table1
---------------------
| | | |
(condition: if inside XML will be node, I want to display second table, under Table1)
SecondTable
-------------
| | |
How I can do this?
This outputs Yep if <AddInfo> exists as immediate child of <Record>, and Nope otherwise:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="Data">
<xsl:for-each select="Records/Record">
<xsl:choose>
<xsl:when test="AddInfo">Yep</xsl:when>
<xsl:otherwise>Nope</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Note that you don't need for-each, you should let a second template match each <Record>:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="Data">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="Data/Records/Record">
<xsl:choose>
<xsl:when test="AddInfo">Yep</xsl:when>
<xsl:otherwise>Nope</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
You could also avoid choose and use two independent if conditions:
<xsl:template match="Data/Records/Record">
<xsl:if test="AddInfo">Yep</xsl:if>
<xsl:if test="not(AddInfo)">Nope</xsl:if>
</xsl:template>
If you don't want to limit it to immediate children, use .//AddInfo instead.
Consider the following stylesheet:
<?xml version="1.0" encoding="utf-8"?>
<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="Data">
<xsl:apply-templates select="Records/Record"/>
</xsl:template>
<xsl:template match="Data/Records/Record">
<table class="one"></table>
<xsl:if test="AddInfo">
<table class="two"></table>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
It outputs
<table class="one"></table>
if there's no <AddInfo> node in <Record>, and
<table class="one"></table>
<table class="two"></table>
otherwise.
You can solve this with neither using if nor choose. XML:
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<Data>
<AddInfo>
<Info>This is ignored</Info>
</AddInfo>
<Records>
<Record>
<AddInfo>
<Info>One,</Info>
<Info>Two,</Info>
<Info>Three</Info>
</AddInfo>
</Record>
<Record>
<Info>Ignored as well</Info>
</Record>
<Record>
<Nested>
<AddInfo>
<Info>So is this</Info>
</AddInfo>
</Nested>
</Record>
</Records>
</Data>
XSLT:
<?xml version="1.0" encoding="utf-8"?>
<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="Data">
<root>
<xsl:apply-templates select="Records/Record"/>
</root>
</xsl:template>
<xsl:template match="Data/Records/Record">
<xsl:copy>
<table id="one"></table>
<xsl:apply-templates select="AddInfo"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Data/Records/Record/AddInfo">
<table id="two">
<xsl:apply-templates select="Info"/>
</table>
</xsl:template>
<xsl:template match="Data/Records/Record/AddInfo/Info">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
Output:
<root>
<Record>
<table id="one" />
<table id="two">One,Two,Three</table>
</Record>
<Record>
<table id="one" />
</Record>
<Record>
<table id="one" />
</Record>
</root>
To check if node exist in xml this XSLT code works
<xsl:choose>
<xsl:when test="XMLNodeName">
<Cell ss:Index="2" ss:StyleID="s110">
<Data ss:Type="String">
<xsl:value-of select="NodeOne"/>
</Data>
</Cell>
</xsl:when>
<xsl:otherwise>
<Cell`enter code here` ss:Index="2" ss:StyleID="s110">
<Data ss:Type="String">
<xsl:value-of select="NodeTwo"/>
</Data>
</Cell>
</xsl:otherwise>
</xsl:choose>

online xml to html parser

I am looking for a online program that parses any xml to html. For instance, if I have the following xml layout
<users>
<user>
</name>john</name>
<pictures>
<pic1>URL of picture1.png</pic1>
<pic2>URL of picture2.png</pic2>
</pictures>
</user>
<user>
</name>mary</name>
<pictures>
<pic1>URL of picture1.png</pic1>
<pic2>URL of picture2.png</pic2>
</pictures>
</user>
</users>
it can create an html page displaying the content of the nodes and give some minimal formatting for easy reading. Any such tool?
Edit: I just gave an example, I want a generic tool that can parse any xml without knowing its structure beforehand.
One way to tackle this would be to apply an XSLT transformation.
You'd need to create an XSL stylesheet, something like...
<?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>
<head>
<title>Contacts</title>
</head>
<body>
<xsl:for-each select="//user">
<h2><xsl:value-of select="name" /></h2>
<p><xsl:value-of select="pictures/pic1" /></p>
<p><xsl:value-of select="pictures/pic2" /></p>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Then link to it at the top of your xml file. In the example below the second line links to the stylesheet named 'myStyleSheet.xsl'.
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="myStyleSheet.xsl"?>
<users>
<user>
<name>john</name>
<pictures>
<pic1>URL of picture1.png</pic1>
<pic2>URL of picture2.png</pic2>
</pictures>
</user>
<user>
<name>mary</name>
<pictures>
<pic1>URL of picture1.png</pic1>
<pic2>URL of picture2.png</pic2>
</pictures>
</user>
</users>
You could try this.
http://www.w3schools.com/xsl/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalog_choose
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<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">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>Artist</th>
</tr>
<xsl:for-each select="catalog/cd">
<tr>
<td><xsl:value-of select="title"/></td>
<xsl:choose>
<xsl:when test="price > 10">
<td bgcolor="#ff00ff">
<xsl:value-of select="artist"/>
</td>
</xsl:when>
<xsl:otherwise>
<td><xsl:value-of select="artist"/></td>
</xsl:otherwise>
</xsl:choose>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

How to call template with name as a variable in XSLT?

I have the following XML document which needs to be parsed with an XSLT to HTML.
<root>
<c>
<c1>
<id>1</id>
<text>US</text>
</c1>
<c1>
<id>2</id>
<text>UK</text>
</c1>
</c>
</root>
The XSLT for converting this to HTML is given below.
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" />
<xsl:template match="root">
<html>
<xsl:for-each select="c/c1">
**<xsl:variable name="vTemplate" select="text"/>
<xsl:apply-templates select="$vTemplate[#name='text'"/>**
</xsl:for-each>
</html>
</xsl:template>
<xsl:template match="xsl:template[#name='text']" name="text">
<select>
<xsl:attribute name="id">
<xsl:value-of select="id"/>
</xsl:attribute>
</select>
</xsl:template>
</xsl:stylesheet>
I need to call a template depends up on the text field. So for the value US, one template will be executed and for UK, another will executed.
How to achieve this with a variable as a template name while calling the template? I just made a try but it gives error. Can someone help me to figure out where i made wrong?
I think it is not possible to choose name of template to be called dynamically. What could be done is xsl:choose utilization (perhaps with combination with mode attribute), like this
<?xml version="1.0" encoding="UTF-8"?>
<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:template match="/root">
<html>
<xsl:for-each select="c/c1">
<xsl:choose>
<xsl:when test="text = 'US'">
<xsl:apply-templates select="text" mode="US"/>
</xsl:when>
<xsl:when test="text = 'UK'">
<xsl:apply-templates select="text" mode="UK"/>
</xsl:when>
<xsl:otherwise>
<xsl:comment>Something's wrong</xsl:comment>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</html>
</xsl:template>
<xsl:template match="text" mode="US">
<xsl:comment>US mode</xsl:comment>
<select>
<xsl:attribute name="id">
<xsl:value-of select="preceding-sibling::id"/>
</xsl:attribute>
</select>
</xsl:template>
<xsl:template match="text" mode="UK">
<xsl:comment>UK mode</xsl:comment>
<select>
<xsl:attribute name="id">
<xsl:value-of select="preceding-sibling::id"/>
</xsl:attribute>
</select>
</xsl:template>
</xsl:stylesheet>
Or you can use match with appropriate predicate and avoid for-each like this
<?xml version="1.0" encoding="UTF-8"?>
<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:template match="/root">
<html>
<xsl:apply-templates select="//c1" />
</html>
</xsl:template>
<xsl:template match="c1[text = 'US']">
<xsl:comment>US mode</xsl:comment>
<select id="{id}" />
</xsl:template>
<xsl:template match="c1[text = 'UK']">
<xsl:comment>UK mode</xsl:comment>
<select id="{id}" />
</xsl:template>
</xsl:stylesheet>
The id attribute of select can be also filled by "Attribute value templates" (xpath in curly brackets) as shown in previous sample.

Counting unique XML element attributes using XSLT

I've just started using XSLT and am trying to figure this out.
Your help would be greatly appreciated.
Example XML file
<purchases>
<item id = "1" customer_id = "5">
</item>
<item id = "2" customer_id = "5">
</item>
<item id = "7" customer_id = "4">
</item>
</purchases>
Desired HTML Output:
<table>
<tr><th>Customer ID</th><th>Number of Items Purchased</th></tr>
<tr><td>5</td><td>2</td></tr>
<tr><td>4</td><td>1</td></tr>
</table>
Customer with id number 5 has bought 2 items.
Customer with id number 4 has bought 1 item.
XSLT 1.0 solution ....
<?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="/">
<table>
<xsl:apply-templates select="purchases/item"/>
</table>
</xsl:template>
<xsl:template match="item">
<xsl:if test="not(
preceding-sibling::*[#customer_id=current()/#customer_id]
)">
<tr><td><xsl:value-of select="#customer_id"/></td>
<td><xsl:value-of select="count(following-sibling::item
[#customer_id=current()/#customer_id])+1"/></td>
</tr>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
A possible Xslt 1.0 solution would be
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:key name="kCustomer" match="item" use="#customer_id"/>
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="purchases">
<xsl:element name="table">
<xsl:element name="tr">
<xsl:element name="th">Customer ID</xsl:element>
<xsl:element name="th">Number of Items Purchased</xsl:element>
<xsl:for-each select="item[generate-id(.) = generate-id(key('kCustomer', #customer_id))]">
<xsl:variable name="total" select="count(/purchases/item[#customer_id=current()/#customer_id]/#id)" />
<xsl:element name="tr">
<xsl:element name="td">
<xsl:value-of select="./#customer_id" />
</xsl:element>
<xsl:element name="td">
<xsl:value-of select="$total" />
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Adopted from Dimitres answer on How can I Group and sort based on sum.
As pointed out by Dimitre the purchases template can be simplified to
<xsl:template match="purchases">
<table>
<tr>
<th>Customer ID</th>
<th>Number of Items Purchased</th>
</tr>
<xsl:for-each select="item[generate-id(.) = generate-id(key('kCustomer', #customer_id))]">
<xsl:variable name="total" select="count(/purchases/item[#customer_id=current()/#customer_id]/#id)" />
<tr>
<td>
<xsl:value-of select="./#customer_id" />
</td>
<td>
<xsl:value-of select="$total" />
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
If you want XSLT 2.0 then the following XSLT should do the trick:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output indent="yes"/>
<xsl:template match="/purchases">
<table>
<tr>
<th>Customer ID</th>
<th>Number of Items Purchased</th>
</tr>
<xsl:for-each-group select="item" group-by="#customer_id">
<tr>
<td>
<xsl:value-of select="current-grouping-key()"/>
</td>
<td>
<xsl:value-of select="count(current-group())"/>
</td>
</tr>
</xsl:for-each-group>
</table>
</xsl:template>
</xsl:stylesheet>