Reputation: 1211
I am new to XSLT and have been struggling with the following problem. I appreciate if anyone could help me how to go around this.
This is my XML file, but the element names could differ each time. The XML is created on the run. Basically I don't know all the elements in the XML file. There could be more or less elements, but basically has the following structure:
<University>
<language>en</language>
<name>Medi University</name>
<location>Rome</location>
<country>Italy</country>
<member>
<teacher>
<name>John Sting</name>
<joined>
<time>
<start/>
<end/>
</time>
<valid>true</valid>
</joined>
<name>Paul Ironman</name>
<joined>
<time>
<start/>
<end/>
</time>
<valid>true</valid>
</joined>
</teacher>
<teacherAssistant>
<name>Luna Tutti</name>
<joined>
<time>
<start>1.9.2015</start>
<end></end>
</time>
<valid>true</valid>
</joined>
</teacherAssistant>
</member>
<telephone>7538476398754</telephone>
<email>[email protected]</email>
</University>
I have this XSLT file that tries to transform that. As I said the XML file is created on run time and I don't know the XML content.
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="*">
<xsl:value-of select="name()"/>
<xsl:value-of select="text()"/>
<xsl:if test="*">
<xsl:apply-templates/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
The above code prints the CSV file like this:
elemenNameelementValue
elemenName2elementValue2
elemenName3elementValue3
and so on.
What I want is something like bellow:
University
language, name, location, country,telephone, email
english, Medi, Rome,Italy,7538476398754,[email protected]
Teacter
name, joined, time, start,end,valid,
John Sting, , , , ,true
Paul Ironman, , , , , true
Teacher Assistant
name, joined, time, start,end,valid,
Luna Tutti, , ,1.9.2015, , true
I want related elements to appear on one line as in above.
Thanks
Upvotes: 0
Views: 2044
Reputation: 14241
Try this truly generic 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="text" omit-xml-declaration="yes" indent="no"/>
<xsl:template match="node()">
<xsl:value-of select="name()"/>
<xsl:text>
</xsl:text>
<xsl:call-template name="loop"/>
</xsl:template>
<xsl:template name="loop">
<!-- Output headers -->
<xsl:for-each select="./*[count(*) = 0]">
<xsl:value-of select="name()"/>
<xsl:if test="position() != last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<!-- Output values -->
<xsl:for-each select="./*[count(*) = 0]">
<xsl:value-of select="."/>
<xsl:if test="position() != last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<!-- Process nodes having childs -->
<xsl:for-each select="./*[count(*) != 0]">
<xsl:value-of select="name()"/>
<xsl:text>
</xsl:text>
<xsl:call-template name="loop"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
As mentioned by michael.hor257k, without some constraints, new table starts for each node having child nodes.
Try this for replacement
<!-- Process nodes having childs -->
<xsl:for-each select="./*[count(*) != 0]">
<xsl:choose>
<xsl:when test="name() = 'teacher'">
<xsl:text>Teacher</xsl:text>
</xsl:when>
<xsl:when test="name() = 'teacherAssistant'">
<xsl:text>Teacher Assistant</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="name()"/>
</xsl:otherwise>
</xsl:choose>
<xsl:text>
</xsl:text>
<xsl:call-template name="loop"/>
</xsl:for-each>
Upvotes: 2
Reputation: 2946
You could use the identity template (as in Using XSLT to copy all nodes in XML, with support for special cases) and work from there.
As an example, with this code
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:value-of select="."/>
<xsl:apply-templates select="@*|node()"/>
</xsl:template>
</xsl:stylesheet>
The output is:
<?xml version="1.0" encoding="UTF-8"?>
en
Medi University
Rome
Italy
John Sting
true
Paul Ironman
true
Luna Tutti
1.9.2015
true
7538476398754
[email protected]
enen
Medi UniversityMedi University
RomeRome
ItalyItaly
John Sting
true
Paul Ironman
true
Luna Tutti
1.9.2015
true
John Sting
true
Paul Ironman
true
John StingJohn Sting
true
truetrue
Paul IronmanPaul Ironman
true
truetrue
Luna Tutti
1.9.2015
true
Luna TuttiLuna Tutti
1.9.2015
true
1.9.2015
1.9.20151.9.2015
truetrue
75384763987547538476398754
[email protected]@medi.com
(note that I had to put a final in your XML
Upvotes: 0