选择具有相对于当前节点属性的属性的节点

时间:2016-10-27 07:39:35

标签: xml xslt xpath hierarchical-data

我有一些看起来像这样的XML:

<root>
  <node id="2_1" name="FOO" />
  <node id="2_2" class="child" />
  <node id="2_3" class="child" />
  <node id="2_4" class="child" />
  <node id="3_1" name="BAR" />
  <node id="3_2" class="child" />
  <node id="3_3" class="child" />
  <node id="3_4" class="child" />
</root>

即,child的父节点id始终共享相同的前缀,但以_1结尾,并且所有子节点后缀从2开始并递增。

我试图产生类似于:

的输出
<groups>
  <group id="2_1">
    <child id="2_2" />
    <child id="2_3" />
    <child id="2_4" />
  </group>
  <group id="3_1">
    <child id="3_2" />
    <child id="3_3" />
    <child id="3_4" />
  </group>
</groups>

我有这个XSLT来获取群组,但我不确定如何选择孩子:

<xsl:template match="/">

<groups>
  <xsl:for-each select="/root/node[@name]">
    <group>
      <xsl:attribute name="id">
        <xsl:value-of select="@id" />
      </xsl:attribute>
    </group>
  </xsl:for-each>
</groups>

</xsl:template>

我是以正确的方式来做这件事的吗?我想我需要一个接受参数的模板,但我不确定如何将该参数分配给当前组的id值。

1 个答案:

答案 0 :(得分:1)

实际上,尽管我发表了评论,但你并不需要在这里进行分组。如果组ID始终以_1结束并且子元素以更高的数字结尾,则可以简化它。

你仍然会创建一个键,但只能匹配

<xsl:key name="nodes" match="node" use="substring-before(@id, '_')" />

然后,如果您从选择_1元素开始,您可以使用键获取子元素

<xsl:apply-templates 
     select="key('nodes', substring-before(@id, '_'))[substring-after(@id, '_') != '1']" />

试试这个XSLT

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

    <xsl:key name="nodes" match="node" use="substring-before(@id, '_')" />

    <xsl:template match="root">
        <groups>
            <xsl:apply-templates select="node[substring-after(@id, '_') = '1']" />
        </groups>
    </xsl:template>

    <xsl:template match="node[substring-after(@id, '_') = '1']">
        <group id="{@id}">
            <xsl:apply-templates select="key('nodes', substring-before(@id, '_'))[substring-after(@id, '_') != '1']" />
        </group>
    </xsl:template>

    <xsl:template match="node">
        <child id="{@id}">
        </child>
    </xsl:template>
</xsl:stylesheet>

或者,如果“group”元素始终具有name属性,而子项不具有,则可以将其略微简化为此...

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

    <xsl:key name="nodes" match="node" use="substring-before(@id, '_')" />

    <xsl:template match="root">
        <groups>
            <xsl:apply-templates select="node[@name]" />
        </groups>
    </xsl:template>

    <xsl:template match="node[@name]">
        <group id="{@id}">
            <xsl:apply-templates select="key('nodes', substring-before(@id, '_'))[not(@name)]" />
        </group>
    </xsl:template>

    <xsl:template match="node">
        <child id="{@id}">
        </child>
    </xsl:template>
</xsl:stylesheet>