简体   繁体   中英

XSLT to convert unknown XML to CSV

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>medi@medi.com</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,medi@medi.com

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

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>&#xA;</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>&#xA;</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>&#xA;</xsl:text>

        <!-- Process nodes having childs -->
        <xsl:for-each select="./*[count(*) != 0]">
            <xsl:value-of select="name()"/>
            <xsl:text>&#xA;</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>&#xA;</xsl:text>
    <xsl:call-template name="loop"/>
</xsl:for-each>

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
medi@medi.com

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
medi@medi.commedi@medi.com

(note that I had to put a final in your XML

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM