如何使用XSLT 1.0转换XML结构

时间:2016-04-07 15:00:48

标签: xml xslt

我是XSLT的新手,但不是XML.I需要转换此结构

Private Function DecodeError(ByVal error As Variant) As String
    On Error Resume Next
    Select Case CLng(error)
        Case xlErrDiv0
            DecodeError = "#DIV/0!"
        Case xlErrNA
            DecodeError = "#N/A"
        Case xlErrName
            DecodeError = "#NAME?"
        Case xlErrNull
            DecodeError = "#NULL!"
        Case xlErrNum
            DecodeError = "#NUM!"
        Case xlErrRef
            DecodeError = "#REF!"
        Case xlErrValue
            DecodeError = "#VALUE!"
        Case Else
            DecodeError = "Unknown error"
    End Select
End Function

详细信息,成绩和年龄标记内的值使用CRLF分隔(分隔符)。

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

我开始知道没有split()函数,我们需要使用递归模板来分割字符串,但是我无法用头来创建所需的输出。

使用.net所以不支持XSLT 2.0。我知道我们可以使用像saxon这样的其他处理器,但我想用XSLT 1.0创建它。

或者,如果是其他任何方式,我也会考虑这一点。

任何帮助都将不胜感激。谢谢。

2 个答案:

答案 0 :(得分:2)

这不是一个很好的解决方案,但更多的是为了表明(如何),即使没有任何扩展,也可以使用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>

答案 1 :(得分:0)

如果您不想迁移到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>

Age元素的计算留给你练习。