XSLT组合父节点具有特定(未知)值的子节点

时间:2017-11-19 20:13:39

标签: xslt

我的XML包含具有相同属性值但具有不同内容的兄弟节点。这发生在父级和子级别,如下所示:

<myxml>
    <a myattr="valuetop1">
        <b myattr="valuechild1">
            <c>Stuff1</c>
            <c>Stuff2</c>
        </b>
    </a>
    <a myattr="valuetop1">
        <b myattr="valuechild2">
            <c>Stuff3</c>
        </b>
    </a>
    <a myattr="valuetop1">
        <b myattr="valuechild2">
            <c>Stuff4</c>
        </b>
    </a>
    <a myattr="valuetop1">
        <b myattr="valuechild2">
            <c>Stuff5</c>
            <c>Stuff6</c>
        </b>
    </a>
    <a myattr="valuetop2">
        <b myattr="valuechild1">
            <c>Stuff1</c>
        </b>
    </a>
    <a myattr="valuetop2">
        <b myattr="valuechild3">
            <c>Stuff2</c>
        </b>
    </a>
    <a myattr="valuetop2">
        <b myattr="valuechild2">
            <c>Stuff3</c>
            <c>Stuff2</c>
        </b>
    </a>
    <a myattr="valuetop2">
        <b myattr="valuechild2">
            <c>Stuff4</c>
        </b>
    </a>
</myxml>

如果存在具有相同属性值的节点存在于同一级别,我想将它们的内容组合在该节点的单个实例下。换句话说,我正在寻找一个整洁的层次结构:

<myxml>
    <a myattr="valuetop1">
        <b myattr="valuechild1">
            <c>Stuff1</c>
            <c>Stuff2</c>
        </b>
        <b myattr="valuechild2">
            <c>Stuff3</c>
            <c>Stuff4</c>
            <c>Stuff5</c>
            <c>Stuff6</c>
        </b>
    </a>        
    <a myattr="valuetop2">
        <b myattr="valuechild1">
            <c>Stuff1</c>
        </b>
        <b myattr="valuechild3">
            <c>Stuff2</c>
        </b>
        <b myattr="valuechild2">
            <c>Stuff3</c>
            <c>Stuff2</c>
            <c>Stuff4</c>
        </b>
    </a>    
</myxml>

问题在于我不知道valuetopx或valuechildx的值是什么。我已经在这个问题上敲了几天,但是不能让我的大脑围绕它。

1 个答案:

答案 0 :(得分:1)

正如评论中所提到的,您可以在XSLT 1.0中使用一种名为Muenchian Grouping的技术,但在您的情况下,您是在两个级别上进行的。

首先,对于父级,您可以像这样定义键

<xsl:key name="parent" match="a" use="@myattr" />

然后,对于孩子,您需要同时考虑父ID和子ID(在子ID可能具有不同父ID的情况下,因此将是不同的组)

<xsl:key name="child" match="b" use="concat(../@myattr, '|', @myattr)" />

然后,为了获得不同的父ID,你可以这样做....

<xsl:apply-templates select="a[generate-id() = generate-id(key('parent', @myattr)[1])]" />

在不同的父级中,为了获得不同的子元素,请执行此操作...

 <xsl:apply-templates select="key('parent', @myattr)/b
                              [generate-id() = generate-id(key('child', concat(../@myattr, '|', @myattr))[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="parent" match="a" use="@myattr" />
  <xsl:key name="child" match="b" use="concat(../@myattr, '|', @myattr)" />

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

  <xsl:template match="myxml">
    <xsl:copy>
      <xsl:apply-templates select="a[generate-id() = generate-id(key('parent', @myattr)[1])]" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="a">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="key('parent', @myattr)/b[generate-id() = generate-id(key('child', concat(../@myattr, '|', @myattr))[1])]" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="b">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="key('child', concat(../@myattr, '|', @myattr))/c" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>