转换XML并将属性添加为元素

时间:2013-04-22 09:37:16

标签: xml xslt

我正在尝试将“test”元素添加到树的最后一个元素中,但它会为每个元素重复:

<root>
   <Module>
      <Router>
         <Message>@OppositeMacAddress='0x00, 0x80, 0xC8, 0x3B, 0xC6, 0xA0'</Message>
         @OppositeMacAddress='0x00, 0x80, 0xC8, 0x3B, 0xC6, 0xA0'
      </Router>
      @OppositeMacAddress='0x00, 0x80, 0xC8, 0x3B, 0xC6, 0xA0'
   </Module> 
</root>

这是我的XML源

   <fired-rule context="Message[@Name='SPY_IN']"/>
       <failed-assert
               test="@OppositeIpAddress='192,168,1,2'"
               location="/Module[1]/Router[1]/Message[1]">
       <text>!Error! Erwarteter Wert:"192,168,1,2"</text>
   </failed-assert>

它应该是这样的:

<root>
   <Module>
      <Router>
         <Message>@OppositeMacAddress='0x00, 0x80, 0xC8, 0x3B, 0xC6, 0xA0'</Message>
      </Router>
   </Module>
</root>

这是我的XSL转换

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

  <xsl:template match="/">
    <root>
      <xsl:apply-templates select="//failed-assert/@location" />
    </root>
  </xsl:template>

  <xsl:template match="@location">
    <xsl:param name="path" select="." />

    <xsl:variable
        name="currentContext" 
        select="substring-before(substring-after($path,'/'), '[')"/>

    <xsl:variable name="subContext" select="substring-after($path, ']')"/>

    <xsl:element name="{$currentContext}">
      <xsl:apply-templates select="current()[string($subContext)]">
        <xsl:with-param name="path" select="$subContext"/>
      </xsl:apply-templates>
      <xsl:value-of select="../@test"/>
    </xsl:element>

  </xsl:template>

</xsl:stylesheet>

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

xsl:element

中尝试此操作
  <xsl:variable name="next" select="current()[string($subContext)]" />

  <xsl:apply-templates select="$next">
    <xsl:with-param name="path" select="$subContext"/>
  </xsl:apply-templates>

  <xsl:value-of select="../@test[not($next)]"/>

完整XSLT:

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

  <xsl:template match="/">
    <root>
      <xsl:apply-templates select="//failed-assert/@location" />
    </root>
  </xsl:template>

  <xsl:template match="@location">
    <xsl:param name="path" select="." />

    <xsl:variable name="currentContext"
                  select="substring-before(substring-after($path,'/'), '[')"/>
    <xsl:variable name="subContext" select="substring-after($path, ']')"/>
    <xsl:element name="{$currentContext}">
      <xsl:variable name="next" select="current()[string($subContext)]" />

      <xsl:apply-templates select="$next">
        <xsl:with-param name="path" select="$subContext"/>
      </xsl:apply-templates>

      <xsl:value-of select="../@test[not($next)]"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

运行样本输入时的结果:

<root>
  <Module>
    <Router>
      <Message>@OppositeIpAddress='192,168,1,2'</Message>
    </Router>
  </Module>
</root>

答案 1 :(得分:1)

我认为更容易理解的解决方案可能是使用call-template。

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

    <xsl:template match="/">
        <root>
            <xsl:apply-templates select="//failed-assert[@location]" />
        </root>
    </xsl:template>

    <xsl:template match="failed-assert">
        <xsl:call-template name="location">
            <xsl:with-param name="path" select="substring-after(@location, '/')" />
            <xsl:with-param name="textmessage" select="@test" />
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="location">
        <xsl:param name="path" />
        <xsl:param name ="textmessage" />

        <xsl:variable name="currentContext"
                      select="substring-before($path,'[')"/>

        <xsl:variable name="subContext" select="substring-after($path, '/')"/>
        <xsl:choose>
            <xsl:when test="$currentContext">
                <xsl:element name="{$currentContext}">
                    <xsl:call-template name="location">
                        <xsl:with-param name="path" select="$subContext" />
                        <xsl:with-param name="textmessage" select="$textmessage" />
                    </xsl:call-template>
                </xsl:element>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$textmessage"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

</xsl:stylesheet>