按兄弟元素对变量中的子项进行分组

grouping children in variable by sibling element

我有一些类似于以下的 XML 数据,存储在 xslt 1 中的变量 中。

<?xml version="1.0" encoding="utf-8"?>
<ItemCollection>
  <Item>
    <Number>1</Number>
    <Data>string 1</Data>
  </Item>
  <Item>
    <Number>1</Number>
    <Data>string 2</Data>
  </Item>
  <Item>
    <Number>2</Number>
    <Data>string 3</Data>
  </Item>
  <Item>
    <Number>2</Number>
    <Data>string 3</Data>
  </Item>
  <Item>
    <Number>3</Number>
    <Data>string 4</Data>
  </Item>
</ItemCollection>

这个变量叫做$collection

我想转换数据,使其具有如下所示的结构:

<?xml version="1.0" encoding="utf-8"?>
<ItemCollection>
  <Item>
    <Number>1</Number>
    <Data>string 1</Data>
    <Data>string 2</Data>
  </Item>
  <Item>
    <Number>2</Number>
    <Data>string 3</Data>
  </Item>
  <Item>
    <Number>3</Number>
    <Data>string 4</Data>
  </Item>
</ItemCollection>

即:Data 具有相同兄弟姐妹 Number(值)的应归为一组。如果 NumberData 相似,则应完全删除 Item 的重复项。在原来的 XML 中,每个 Item 正好 一个 Number 和一个 Data - 我想改变这个所以它仍然会只有一个 Number,但有几个 Data.

XML 数据,如前所述,位于上方的变量 内。我尝试了不同的方法,例如使用两个 xsl:for-each 将变量迭代两次(使用 exsl:node-set($collection)//Item),但这只会产生数据的排序顺序,这没有多大用处。

这是我目前拥有的 XSLT(只有一个片段,如果需要可以 post 更多)

<xsl:variable name="collection" select="'XMl DATA'"/>
<xsl:variable name="final">
  <xsl:for-each select="exsl:node-set($collection)//Item">
    <xsl:variable name="outer" select="."/>
    <xsl:for-each select="exsl:node-set($collection)//Item">
      <xsl:variable name="inner" select="."/>
      <xsl:if test="$inner = $outer">
        <Item>
          <xsl:value-of select="$outer/Number"/>
          <xsl:copy-of select="$inner/Data"/>
        </Item>
      </xsl:if>
    </xsl:for-each>
  </xsl:for-each>
</xsl:variable>
<xsl:copy-of select="$final" />

编辑:

非常感谢您的回答。我意识到结果包含这样的重复项:

<Item>
    <Number>2039205</Number>
    <Data>String 1</Data>
    <Data>String 1</Data>
    <Data>String 1</Data>
</tns:Item>

有没有简单的方法也可以删除它们?我尝试声明另一个 xsl:key

<xsl:key name="item-by-data" match="Item" use="Data"/> 然后做:

  <xsl:template match="Item">
    <xsl:copy>
      <xsl:copy-of select="Number| key('item-by-data', Number)/Data[generate-id() = generate-id(key('item-by-data', Data)[1])]"/>
    </xsl:copy>
  </xsl:template>

但这删除了所有项目,而不仅仅是重复项。

在您获得的节点集上使用 Muenchian grouping <xsl:param name="col-ns" select="exsl:node-set($collection)"/>,即定义一个key

<xsl:key name="item-by-number" match="Item" use="Number"/>

然后有

<xsl:template match="ItemCollection">
  <xsl:copy>
    <xsl:apply-templates select="Item[generate-id() = generate-id(key('item-by-number', Number)[1])]"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="Item">
  <xsl:copy>
    <xsl:copy-of select="Number | key('item-by-number', Number)/Data"/>
  </xsl:copy>
</xsl:template>

那么你只需要在你需要转换内容的地方有<xsl:apply-templates select="$col-ns/node()"/>就可以了

完整样本位于 http://xsltransform.net/gWmuiJc

如果你还想消除重复的 Data 那么你可以使用 <xsl:key name="numbered-items-by-data" match="Item" use="concat(Number, '|', Data)"/>

<xsl:template match="Item">
  <xsl:copy>
    <xsl:copy-of select="Number | key('item-by-number', Number)[generate-id() = generate-id(key('numbered-items-by-data', concat(Number, '|', Data))[1])]/Data"/>
  </xsl:copy>
</xsl:template>

样本位于 http://xsltransform.net/gWmuiJc/2