通过兄弟元素将变量分组为变量

时间:2015-01-13 14:42:48

标签: xml xslt xslt-1.0

我有一些类似于以下的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(值)的Item应归为一组。如果NumberData两者相似,则应完全删除Item&s的重复项。在原始XML中,每个Number都有完全一个Data和一个Number - 我想要更改它,因此它仍然只有一个{{1} },但有几个Data

如上所述,XML数据是变量中的,位于上方。我尝试了不同的事情,例如使用两个xsl:for-each来迭代变量两次(使用exsl:node-set($collection)//Item),但这只产生了数据的排序顺序,这没什么用处。 / p>

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

<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>

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

1 个答案:

答案 0 :(得分:1)

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

<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