简体   繁体   English

如何使用XSLT 1.0转换XML结构

[英]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 我对XSLT非常陌生,但对XML则不是。我需要转换这种结构

<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. 使用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. 我知道没有split()函数,我们需要使用递归模板来拆分字符串,但是无法包扎头来创建所需的输出。

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. 我正在使用.net,因此不支持XSLT 2.0。我知道我们可以使用其他处理器,例如saxon,但是我想使用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. 这不是一个很好的解决方案,而是更多地证明了XSLT 1.0即使没有任何扩展也可以做到这一点。

<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 : 如果您不想转移到XSLT 2.0处理器,请利用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. Age元素的计算留给您作为练习。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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