简体   繁体   中英

How to transform the XML structure using XSLT 1.0

I am very new to XSLT but not to XML.I need to transform this structure

<Data>
<Details>Good
Bad
Normal
</Details>
<Grade>A
B
</Grade>
<Age>50
60
</Age>
</Data>

Values inside Details, Grade and Age tag are separated(delimiter) using CRLF.

into

 <PersonDetails>
    <Details>
       <Type>Good</Type>
       <Grade>A</Grade>
       <Age>50</Age>
    </Details>
    <Details>
       <Type>Bad</Type>
       <Grade>B</Grade>
       <Age>60</Age>
    </Details>
    <Details>
       <Type>Normal</Type>
       <Grade></Grade>
       <Age></Age>
    </Details>
  </PersonDetails>

I came to know that there is no split() function and we need to use recursive template to split the strings but am not able to wrap my head to create the required output.

Am using .net so XSLT 2.0 is not supported.I know we can use other processor like saxon, but I would like to create it using XSLT 1.0.

Or if it is any other way I will consider that too.

Any help would be appreciated.Thank you.

This is not a nice solution, but more to show that (an how) it is also possible with XSLT 1.0 even without any extension.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  version="1.0">
    <xsl:output method="xml"  indent="yes" />

    <xsl:template match="Data">
        <PersonDetails>
        <xsl:apply-templates select="Details" />
        </PersonDetails>
    </xsl:template>
    <xsl:template match="Details">

        <xsl:call-template name="genDetails">
            <xsl:with-param name="text" select="." />
            <xsl:with-param name="pos" select="3" />
        </xsl:call-template>

    </xsl:template>

    <xsl:template name ="genDetails">
        <xsl:param name="text"/>
        <xsl:param name="count" select="1" />
        <xsl:param name="char" select="'&#10;'" />
        <xsl:choose>
            <xsl:when test="$text != '' ">

                <Details>

                    <Type>
                        <xsl:value-of select="normalize-space(substring-before($text, $char))"/>
                    </Type>
                    <Grade>
                        <xsl:call-template name="gettext">
                            <xsl:with-param name="text" select="../Grade" />
                            <xsl:with-param name="pos" select="$count" />
                            <xsl:with-param name="char" select="$char" />
                        </xsl:call-template>
                    </Grade>
                    <Age>
                        <xsl:call-template name="gettext">
                            <xsl:with-param name="text" select="../Age" />
                            <xsl:with-param name="pos" select="$count" />
                            <xsl:with-param name="char" select="$char" />
                        </xsl:call-template>
                    </Age>
                </Details>
                <xsl:if test="contains($text, $char)">
                    <xsl:call-template name="genDetails">
                        <xsl:with-param name="text" select="substring-after($text, $char)" />
                        <xsl:with-param name="count" select="$count  + 1" />
                        <xsl:with-param name="char" select="$char" />
                    </xsl:call-template>
                </xsl:if>
            </xsl:when>
            <xsl:otherwise>
                <xsl:text><!-- empty text --></xsl:text>
            </xsl:otherwise>
        </xsl:choose>

    </xsl:template>

    <xsl:template name ="gettext">
        <xsl:param name="text"/>
        <xsl:param name="pos" select="1" />
        <xsl:param name="count" select="1" />
        <xsl:param name="char" select="'&#13;'" />

        <xsl:choose>
            <xsl:when test="$count = $pos">
                <xsl:value-of select="normalize-space(substring-before($text, $char))"/>
            </xsl:when>
            <xsl:when test="contains($text, $char)">
                <xsl:call-template name="gettext">
                    <xsl:with-param name="text" select="substring-after($text, $char)" />
                    <xsl:with-param name="pos" select="$pos" />
                    <xsl:with-param name="count" select="$count  + 1" />
                    <xsl:with-param name="char" select="$char" />
                </xsl:call-template>

            </xsl:when>
            <xsl:otherwise>
                <xsl:text><!-- empty text --></xsl:text>
            </xsl:otherwise>
        </xsl:choose>

    </xsl:template>

</xsl:stylesheet>

If you don't want to move to an XSLT 2.0 processor then make use of existing libraries like EXSLT http://exslt.org/str/functions/tokenize/index.html :

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  xmlns:exsl="http://exslt.org/common"
  xmlns:str="http://exslt.org/strings"
  exclude-result-prefixes="msxsl exsl str">

  <xsl:import href="http://exslt.org/str/functions/tokenize/str.tokenize.template.xsl"/>

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="Data">
    <PersonDetails>
      <xsl:variable name="det-rtf">
        <xsl:call-template name="str:tokenize">
          <xsl:with-param name="string" select="Details"/>
          <xsl:with-param name="delimiters" select="'&#13;&#10;'"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:variable name="det" select="exsl:node-set($det-rtf)/token[normalize-space()]"/>

      <xsl:variable name="grade-rtf">
        <xsl:call-template name="str:tokenize">
          <xsl:with-param name="string" select="Grade"/>
          <xsl:with-param name="delimiters" select="'&#13;&#10;'"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:variable name="grade" select="exsl:node-set($grade-rtf)/token[normalize-space()]"/>

      <xsl:for-each select="$det">
        <xsl:variable name="pos" select="position()"/>
        <Details>
          <Type>
            <xsl:value-of select="normalize-space()"/>
          </Type>
          <Grade>
            <xsl:value-of select="normalize-space($grade[$pos])"/>
          </Grade>
        </Details>
      </xsl:for-each>
    </PersonDetails>
  </xsl:template>

</xsl:stylesheet>

The computation of the Age elements is left as an exercise to you.

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