简体   繁体   中英

How to create xsl from xml child node text?

Its fair that i put some effort in trying out this myself first, here is my xml code. My xsl works fine but i can only get to the parent node and i dont know how to get the text from the child element(Entries\\Reference)

         <?xml version="1.0"?>
     <Catalog>
          <Book id="bk101">
             <Author>Garghentini, Davide</Author>
              <Title>XML Developer's Guide</Title>
              <Genre>Computer</Genre>
              <Price>44.95</Price>
               <a:Entries>
                  <a:Reference>
                       <a:ISBN>a0WER8501d2b60c73567f83</a:ISBN>
                       <a:Description>Classics</a:Description>                
                       <a:EventDate>2015-08-25T00:00:00</a:EventDate>
                       <a:UnitCost>750.0000</a:UnitCost>
                       <a:UnitPrice>1380.0000</a:UnitPrice>
                       <a:UnitPriceInBaseCurrency>1380.0000</a:UnitPriceInBaseCurrency>
                 </a:Reference>
                 <a:Reference>
                       <a:ISBN>a0cVSFWREW01d2b60c73567f83</a:ISBN>
                       <a:Description>horror</a:Description>                
                       <a:EventDate>2015-6-25T00:00:00</a:EventDate>
                       <a:UnitCost>150.0000</a:UnitCost>
                       <a:UnitPrice>130.0000</a:UnitPrice>
                       <a:UnitPriceInBaseCurrency>130.0000</a:UnitPriceInBaseCurrency>
                  </a:Reference>
               </a:Entries>
                <PublishDate>2000-10-01</PublishDate>
                <Description>applications  with XML.</Description>
           </Book>
           <Book id="bk102">
                    <Author>Garcia, Debra</Author>
                    <Title>Midnight Rain</Title>
                    <Genre>Fantasy</Genre>
                    <Price>5.95</Price>
                    <PublishDate>2000-12-16</PublishDate>
                    <Description>A former architect battles corporate zombies.</Description>
           </Book>
     </Catalog>

This is my xsl:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" >
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">Author,Title,Genre,Price,PublishDate,Description
<xsl:for-each select="//Book">
<xsl:value-of select="concat( Author,',',Title,',',Genre,',',Price,',',PublishDate,',',Description,'&#xA;')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

and this is the output in csv

Author,Title,Genre,Price,PublishDate,Description
Garghentini, Davide,XML Developer's     
Guide,Computer,44.95,2000-10-01,applications  with XML.
Garcia, Debra,Midnight Rain,Fantasy,5.95,2000-12-16,A former architect 
battles corporate zombies.

But i want to also get the output from the child element so i want to see something like this and also its values.i dont know how i can achieve this.

Author,Title,Genre,Price,PublishDate,Description,ISBN,Description,EventDate,UnitCost

Well, before you edited your question I wrote a very complex xslt, that produces almost exactly the required output for any xml with similar structure. Just want to leave it here

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">

  <xsl:output method="text" />

  <xsl:key name="key" match="*" use="concat(name(..),':',name())"/>

  <xsl:variable name="headers" select="//*[not(*)][count(key('key', concat(name(..),':',name()))[1]|.) = 1]"/>

  <xsl:variable name="colsx">
    <xsl:for-each select="$headers">
        <xsl:variable name="p" select="position()"/>
        <col>
            <num>
                <xsl:value-of select="position()"/>
            </num>
            <level>
                <xsl:value-of select="count(ancestor::*)-1"/>
            </level>
            <pos>
                <xsl:value-of select="count($headers[position() &lt; $p and count(ancestor::*)=count(current()/ancestor::*)])"/>
            </pos>
            <name>
                <xsl:value-of select="concat(name(..),':',name())"/>
            </name>
      <parent>
        <xsl:value-of select="name(..)"/>
      </parent>
        </col>
    </xsl:for-each>
  </xsl:variable>

  <xsl:variable name="cols" select="msxsl:node-set($colsx)"/>

  <xsl:variable name="maxlevel">
    <xsl:for-each select="$cols/col">
      <xsl:sort select="level" order="descending"/>
      <xsl:if test="position() = 1">
        <xsl:value-of select="level"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <xsl:template match="/">

    <xsl:for-each select="$headers">
        <xsl:value-of select="concat(name(..),':',name())"/>
        <xsl:text>&#x9;</xsl:text>
    </xsl:for-each>


    <xsl:text>&#x0D;&#x0A;</xsl:text>

    <xsl:apply-templates select="*/*">
        <xsl:with-param name="level" select="1"/>
    </xsl:apply-templates>

  </xsl:template>

  <xsl:template match="*[*]">
      <xsl:param name="level"/>

    <xsl:variable name="children" select="*"/>
    <xsl:variable name="num" select="$cols/col[level = $level and parent = name(current())][1]/num"/>

    <xsl:if test="position() > 1">
          <xsl:for-each select="$cols/col[num &lt; $num]">
              <xsl:text>-&#x09;</xsl:text>
          </xsl:for-each>
      </xsl:if>

    <xsl:for-each select="$cols/col[level = $level and parent = name(current())]">
      <xsl:choose>
        <xsl:when test="$children[not(*)][concat(name(..),':',name()) = current()/name]">
          <xsl:value-of select="$children[not(*)][concat(name(..),':',name()) = current()/name]"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>-</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text>&#x9;</xsl:text>
    </xsl:for-each>

      <xsl:choose>
          <xsl:when test="$level &lt; $maxlevel and *[*]">
              <xsl:apply-templates select="*[*]">
                  <xsl:with-param name="level" select="$level + 1"/>
        </xsl:apply-templates>
          </xsl:when>
          <xsl:when test="$level &lt; $maxlevel and not(*[*])">
              <xsl:for-each select="$cols/col[num &gt; $num + count($cols/col[level = $level and parent = name(current())]) - 1]">
                  <xsl:text>-&#x09;</xsl:text>
              </xsl:for-each>
              <xsl:text>&#x0D;&#x0A;</xsl:text>
          </xsl:when>
          <xsl:otherwise>
              <xsl:text>&#x0D;&#x0A;</xsl:text>
          </xsl:otherwise>
      </xsl:choose>
  </xsl:template>


</xsl:stylesheet>

So it produces the following output:

bookinfo:title  part:title  chapter:title   chapter:para    
Beginning XML   -   -   -   
-   First Part  What is XML?    bla bla 
-   -   Well-Formed XML.    bla bla 
-   Second Part     XML Namespaces. bla bla 
-   -   XSLT.   bla bla 

XML in question was

<?xml version="1.0" encoding="utf-8"?>
<book>
    <bookinfo>
        <title>Beginning XML</title>
    </bookinfo>
    <part>
        <title>First Part </title>
        <chapter>
            <title>What is XML?</title>
            <para>bla bla</para>
        </chapter>
     <chapter>
        <title>Well-Formed XML.</title>
        <para>bla bla</para>
     </chapter>
   </part>
   <part>
    <title>Second Part </title>
    <chapter>
        <title>XML Namespaces.</title>
       <para>bla bla</para>
    </chapter>
     <chapter>
        <title>XSLT.</title>
       <para>bla bla</para>
     </chapter>
   </part>
 </book>

With the desired result as

Bookinfo:title  part:title   chapter:title    chapter:para

Beginning XML    First Part  What is XML?     bla bla
                             Well-Formed XML  bla bla      

This is definitely not the stylesheet that you want to start learning XSLT with :)

Please, try my code:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fo="http://www.w3.org/1999/XSL/Format"
                xmlns:a="your:namespace">

    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>

    <xsl:template match="/">

        <!-- Create header -->
        <xsl:for-each select="//Book[1]/*[namespace-uri() != 'your:namespace']">
            <xsl:value-of select="name()"/>
            <xsl:text>,</xsl:text>
        </xsl:for-each>

        <xsl:for-each select="//Book/a:Entries/a:Reference/*">
            <xsl:if test="position() != 1">
                <xsl:text>,</xsl:text>
            </xsl:if>
            <xsl:value-of select="local-name()"/>
        </xsl:for-each>

        <xsl:text>&#xA;</xsl:text>

        <!-- Create body -->
        <xsl:for-each select="//Book">
            <xsl:for-each select="./*[namespace-uri() != 'your:namespace']">
                <xsl:call-template name="test-comma">
                    <xsl:with-param name="value" select="."/>
                </xsl:call-template>
                <xsl:text>,</xsl:text>
            </xsl:for-each>

            <xsl:for-each select="a:Entries/a:Reference/*">
                <xsl:if test="position() != 1">
                    <xsl:text>,</xsl:text>
                </xsl:if>
                <xsl:call-template name="test-comma">
                    <xsl:with-param name="value" select="."/>
                </xsl:call-template>
            </xsl:for-each>
            <xsl:text>&#xA;</xsl:text>
        </xsl:for-each>

    </xsl:template>

    <xsl:template name="test-comma">
        <xsl:param name="value"/>

        <xsl:choose>
            <xsl:when test="contains($value, ',')">
                <xsl:text>&quot;</xsl:text>
                <xsl:value-of select="$value"/>
                <xsl:text>&quot;</xsl:text>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$value"/>
            </xsl:otherwise>
        </xsl:choose>

    </xsl:template>

</xsl:stylesheet>

Specify the correct namespace instead of your:namespace .

Note that the values that contain a comma must be enclosed in quotes to get the correct csv.

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