按兄弟元素对变量中的子项进行分组
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
(值)的应归为一组。如果 Number
和 Data
相似,则应完全删除 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>
我有一些类似于以下的 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
(值)的应归为一组。如果 Number
和 Data
相似,则应完全删除 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>