如何只根据某个节点的属性值修改其他节点?

时间:2017-03-07 14:51:31

标签: xml xslt xpath

我正在尝试转换这些数据:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
  <branch link="1" type="band" value="">
    <leaf/>
    <branch link="1" type="band/mhz" value="some">
      <leaf/>
    </branch>
    <branch link="1" type="band/other" value="thing">
      <leaf/>
    </branch>
  </branch>
  <branch link="1" type="member" value="">
    <leaf/>
    <branch link="1" type="member/kind" value="a">
      <leaf/>
    </branch>
  </branch>
  <branch link="2" type="member" value="">
    <leaf/>
    <branch link="2" type="member/kind" value="b">
      <leaf/>
    </branch>
  </branch>
</root>

得到这个:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
  <branch link="" type="other" value="thing">
    <leaf/>
  </branch>
  <branch link="" type="member-info" value="">
    <leaf/>
    <branch link="" type="member-info/kind" value="a">
      <leaf/>
    </branch>
  </branch>
  <branch link="2" type="member" value="">
    <leaf/>
    <branch link="2" type="member/kind" value="b">
      <leaf/>
    </branch>
  </branch>
</root>

我正在使用这个XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes" method="xml"/>

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

  <xsl:template match="branch[starts-with(@name, 'band')]">

    <xsl:for-each select="current()/*">
      <xsl:if test="@name = 'band/other'">
        <xsl:variable name="linkId" select="@link"/>

        <xsl:for-each select="../../branch[@link=$linkId and @name='member']">
          <branch>
            <xsl:attribute name="name">
              <xsl:value-of select="replace(@name, 'member', 'member-info')"/>
            </xsl:attribute>
            <xsl:for-each select="@*[.]">
              <xsl:if test="local-name() != 'name'">
                <xsl:attribute name="{local-name()}">
                  <xsl:if test="local-name() != 'link'">
                    <xsl:value-of select="."/>
                  </xsl:if>
                </xsl:attribute>
              </xsl:if>
            </xsl:for-each>

            <xsl:for-each select="./*">
              <branch>
                <xsl:attribute name="name">
                  <xsl:value-of
                    select="replace(@name, 'member', 'member-info')"/>
                  </xsl:attribute>
                  <xsl:for-each select="@*[.]">
                    <xsl:if test="local-name() != 'name'">
                      <xsl:attribute name="{local-name()}">
                        <xsl:if test="local-name() != 'link'">
                          <xsl:value-of select="."/>
                        </xsl:if>
                      </xsl:attribute>
                    </xsl:if>
                  </xsl:for-each>
                  <xsl:apply-templates/>
                </branch>
              </xsl:for-each>
            </branch>
            <xsl:apply-templates/>
          </xsl:for-each>

          <xsl:copy>
            <xsl:attribute name="name">
              <xsl:value-of select="replace(@name, 'band/', '')"/>
            </xsl:attribute>
            <xsl:for-each select="@*[.]">
              <xsl:if test="local-name() != 'name'">
                <xsl:attribute name="{local-name()}">
                  <xsl:if test="local-name() != 'link'">
                    <xsl:value-of select="."/>
                  </xsl:if>
                </xsl:attribute>
              </xsl:if>
            </xsl:for-each>
            <xsl:apply-templates/>
          </xsl:copy>
        </xsl:if>
      </xsl:for-each>

    </xsl:template>

    <xsl:template match="branch[@name='member' and @link='']"/>

  </xsl:stylesheet>

所以,我正在尝试:

  1. “向上移动逻辑级别”元素匹配<branch type="band/other">以获取<branch type="other">,同时清除link属性并丢弃父级和其他兄弟级别 - &gt;的确定

  2. 然后,对于第1部分中的元素,找到具有相同<branch type="member"> attr的link。值(例如“1”)并通过将“-info”附加到属性branch的“成员”值 - &gt;来重命名它们(以及它们的type子项)的 NOK

  3. 保留其他元素 - &gt;的确定

  4. 第2部分的问题:

    • original(unrenamed,link =“1”)“member / kind”仍为
    • 原创(unrenamed,link =“1”)“会员”和儿童“会员/亲属”仍然

    我该如何解决?我是否需要一种不同的方法(命名为tempalted)?

1 个答案:

答案 0 :(得分:0)

我认为你可以匹配模板中的元素,只需操作属性:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

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

    <xsl:template match="branch[.//branch[@type = 'band/other']]">
        <xsl:apply-templates select=".//branch[@type = 'band/other']"/>
    </xsl:template>

    <xsl:template match="branch[@type = 'band/other']/@type">
        <xsl:attribute name="type" select="replace(., 'band/', '')"/>
    </xsl:template>

    <xsl:template match="branch[@type = 'band/other']/@link | branch[@type[starts-with(., 'member')] and @link = //branch[@type = 'band/other']/@link]/@link">
        <xsl:attribute name="link"></xsl:attribute>
    </xsl:template>

    <xsl:template match="branch[@type[starts-with(., 'member')] and @link = //branch[@type = 'band/other']/@link]/@type">
        <xsl:attribute name="member" select="replace(., 'member', 'member-info')"/>
    </xsl:template>
</xsl:transform>

http://xsltransform.net/94AbWC3/1

使用XSLT 3,我们可以将值存储在变量中,并使用键来查找引用的项目:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    exclude-result-prefixes="xs math"
    version="3.0">

    <xsl:variable name="change" select="//branch[@type = 'band/other']"/>

    <xsl:key name="ref" match="branch[@type[starts-with(., 'member')]]" use="@link"/>

    <xsl:variable name="change-ref" select="key('ref', $change/@link)"/>

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

    <xsl:template match="branch[.//branch[@type = 'band/other']]">
        <xsl:apply-templates select=".//branch[@type = 'band/other']"/>
    </xsl:template>

    <xsl:template match="$change/@type">
        <xsl:attribute name="type" select="replace(., 'band/', '')"/>
    </xsl:template>

    <xsl:template match="$change/@link | $change-ref/@link">
        <xsl:attribute name="link"></xsl:attribute>
    </xsl:template>

    <xsl:template match="$change-ref/@type">
        <xsl:attribute name="member" select="replace(., 'member', 'member-info')"/>
    </xsl:template>

</xsl:stylesheet>