String使用XSL 1.0拆分为新元素

时间:2017-10-28 17:00:14

标签: xslt

可以指导我根据令牌将给定的xml元素值拆分为多个子元素。这是我的示例输入xml和所需的输出。我有使用xsl 1.0的限制。谢谢。

输入XML:

    <?xml version='1.0' encoding='UTF-8'?>
<SQLResults>
    <SQLResult>
        <ACTION1>Action1</ACTION1>
        <ACTION2>Action2</ACTION2>
        <Encrypt>Program=GPG;Code=23FCS;</Encrypt>
        <SENDER>Program=WebPost;Protocol=WS;Path=/home/Inbound</SENDER>
    </SQLResult>
</SQLResults>

输出XML:

<?xml version='1.0' encoding='UTF-8'?>
<SQLResults>
    <SQLResult>
        <ACTION1>Action1</ACTION1>
        <ACTION2>Action2</ACTION2>
        <Encrypt>
            <Program>GPG</Program>
            <Code>23FCS</Code>
        </Encrypt>
        <SENDER>
            <Program>Action4</Program>
            <Protocol>WS</Protocol>
            <Path>/home/Inbound</Path>
        </SENDER>
    </SQLResult>
</SQLResults>

1 个答案:

答案 0 :(得分:1)

XSLT 2中,只需使用以下模板即可:

<xsl:template match="Encrypt|SENDER">
  <xsl:copy>
    <xsl:analyze-string select="." regex="(\w+)=([\w/]+);?">
      <xsl:matching-substring>
        <element name="{regex-group(1)}">
          <xsl:value-of select="regex-group(2)"/>
        </element>
      </xsl:matching-substring>
    </xsl:analyze-string>
  </xsl:copy>
</xsl:template>

因为你想在XSLT 1中这样做,你必须用另一种方式表达。

而不是analyze-string,你必须:

  • 将内容标记为;个字符之间包含的非空标记。 您必须添加tokenize模板。
  • 每个此类标记在=字符之前和之后分为2个子字符串。
  • 创建一个名称等于第一个子字符串的元素。
  • 写下此元素的内容 - 第二个子字符串。

XSLT 1也有tokenize模板的结果限制 是结果树片段(RTF)而不是节点集因此它不能是 用于XPath表达式。

要规避此限制,您必须使用exsl:node-set功能。

所以整个脚本如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common">
  <xsl:output method="xml" encoding="UTF-8" indent="yes" />
  <xsl:strip-space elements="*"/>

  <xsl:template match="Encrypt|SENDER">
    <xsl:copy>
      <xsl:variable name="tokens">
        <xsl:call-template name="tokenize">
          <xsl:with-param name="txt" select="."/>
          <xsl:with-param name="delim" select="';'"/>
        </xsl:call-template> 
      </xsl:variable>
      <xsl:for-each select="exsl:node-set($tokens)/token">
        <xsl:variable name="t1" select="substring-before(., '=')"/>
        <xsl:variable name="t2" select="substring-after(., '=')"/>
        <xsl:element name="{$t1}">
          <xsl:value-of select="$t2" />
        </xsl:element>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

  <xsl:template name="tokenize">
    <xsl:param name="txt" />
    <xsl:param name="delim" select="' '" />
    <xsl:choose>
      <xsl:when test="$delim and contains($txt, $delim)">
        <token>
          <xsl:value-of select="substring-before($txt, $delim)" />
        </token>
        <xsl:call-template name="tokenize">
          <xsl:with-param name="txt" select="substring-after($txt, $delim)" />
          <xsl:with-param name="delim" select="$delim" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$txt">
        <token><xsl:value-of select="$txt" /></token>
      </xsl:when>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
  </xsl:template>
</xsl:transform>