我想使用XSLT修改:
<Office Code="1" OtherAttribute="5">
<Customer CustomerId="0010" CodeModifier="A"/>
<Customer CustomerId="0011" CodeModifier="B"/>
<Customer CustomerId="0012" CodeModifier="B"/>
</Office>
<Office Code="2" OtherAttribute="6">
<Customer CustomerId="2010" CodeModifier="A"/>
<Customer CustomerId="0011" CodeModifier="C"/>
</Office>
进入:
<Office Code="1A" OtherAttribute="5">
<Customer CustomerId="0010"/>
</Office>
<Office Code="1B" OtherAttribute="5">
<Customer CustomerId="0011"/>
<Customer CustomerId="0012"/>
</Office>
<Office Code="2A" OtherAttribute="6">
<Customer CustomerId="2010"/>
</Office>
<Office Code="2C" OtherAttribute="6">
<Customer CustomerId="0011"/>
</Office>
我的目标:
有人知道该怎么做吗?
答案 0 :(得分:2)
此样式表适用于您的输入样本:
<!-- a key to group Customers by their office code + modifier -->
<xsl:key name="kCustomerGroup" match="Customer"
use="concat(../@Code, @CodeModifier)"
/>
<!-- identity template: copies everything that is not handled otherwise -->
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<!-- apply templates directly to customers. modify as necessary -->
<xsl:template match="/">
<xsl:apply-templates select="//Customer" mode="CustomerGroup" />
</xsl:template>
<xsl:template match="Customer" mode="CustomerGroup">
<xsl:variable name="officeCode" select="concat(../@Code, @CodeModifier)" />
<!-- if this Customer is first of his respective group... -->
<xsl:if test="
generate-id()
=
generate-id(key('kCustomerGroup', $officeCode)[1])
">
<!-- use for-each to switch the context node to the parent -->
<xsl:for-each select="..">
<xsl:copy>
<xsl:apply-templates select="@*" />
<!-- overwrite the @Code attribute -->
<xsl:attribute name="Code">
<xsl:value-of select="$officeCode" />
</xsl:attribute>
<!-- now handle the Customer group members -->
<xsl:apply-templates select="key('kCustomerGroup', $officeCode)" />
</xsl:copy>
</xsl:for-each>
</xsl:if>
</xsl:template>
<!-- remove unwanted attribute with empty template -->
<xsl:template match="Customer/@CodeModifier" />
返回
<Office Code="1A" OtherAttribute="5">
<Customer CustomerId="0010"></Customer>
</Office>
<Office Code="1B" OtherAttribute="5">
<Customer CustomerId="0011"></Customer>
<Customer CustomerId="0012"></Customer>
</Office>
<Office Code="2A" OtherAttribute="6">
<Customer CustomerId="2010"></Customer>
</Office>
<Office Code="2C" OtherAttribute="6">
<Customer CustomerId="0011"></Customer>
</Office>
请注意
Customer
分组制作了一个模板。正常节点处理发生在身份模板中。xsl:for-each
循环来更改xsl:copy
的上下文节点。xsl:copy
复制属性, 稍后会覆盖其中一个属性。要强制执行特定订单,请使用以下内容:
<xsl:apply-templates select="//Customer" mode="CustomerGroup">
<xsl:sort select="../@Code" data-type="text" order="ascending" />
</xsl:apply-templates>
和
<xsl:apply-templates select="key('kCustomerGroup', $officeCode)">
<xsl:sort select="@CodeModifier" data-type="number" order="ascending" />
</xsl:apply-templates>
答案 1 :(得分:1)
这是另一种方法,仅使用匹配模板。
在 MSXSL 4.0
下测试 XSLT 1.0<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" indent="yes"/>
<xsl:key name="kCustomerGroup" match="Customer"
use="concat(../@Code, @CodeModifier)"
/>
<xsl:template match="Office">
<xsl:apply-templates select="Customer[generate-id()
=
generate-id(key('kCustomerGroup',
concat(../@Code, @CodeModifier))[1])]"
/>
</xsl:template>
<xsl:template match="Customer">
<Office
Code="{concat(../@Code,@CodeModifier)}"
OtherAttribute="{../@OtherAttribute}">
<xsl:apply-templates select="key('kCustomerGroup',
concat(../@Code,@CodeModifier))" mode="copy"/>
</Office>
</xsl:template>
<xsl:template match="Customer" mode="copy">
<xsl:copy>
<xsl:copy-of select="@CustomerId"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
输出到:
<?xml version="1.0" encoding="UTF-8"?>
<Office Code="1A" OtherAttribute="5">
<Customer CustomerId="0010"/>
</Office>
<Office Code="1B" OtherAttribute="5">
<Customer CustomerId="0011"/>
<Customer CustomerId="0012"/>
</Office>
<Office Code="2A" OtherAttribute="6">
<Customer CustomerId="2010"/>
</Office>
<Office Code="2C" OtherAttribute="6">
<Customer CustomerId="0011"/>
</Office>
答案 2 :(得分:1)
完整而简短的XSLT 2.0解决方案:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*/*">
<xsl:for-each-group select="Customer" group-by="@CodeModifier">
<Office>
<xsl:copy-of select="../@*"/>
<xsl:attribute name="Code" select=
"concat(../@Code, current-grouping-key())"/>
<xsl:copy-of select="current-group()"/>
</Office>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
应用于以下XML文档(基于提供的XML片段并将其包装到单个顶部元素中以使其成为格式良好的XML文档):
<company>
<Office Code="1" OtherAttribute="5">
<Customer CustomerId="0010" CodeModifier="A"/>
<Customer CustomerId="0011" CodeModifier="B"/>
<Customer CustomerId="0012" CodeModifier="B"/>
</Office>
<Office Code="2" OtherAttribute="6">
<Customer CustomerId="2010" CodeModifier="A"/>
<Customer CustomerId="0011" CodeModifier="C"/>
</Office>
</company>
生成想要的正确结果:
<Office Code="1A" OtherAttribute="5">
<Customer CustomerId="0010" CodeModifier="A"/>
</Office>
<Office Code="1B" OtherAttribute="5">
<Customer CustomerId="0011" CodeModifier="B"/>
<Customer CustomerId="0012" CodeModifier="B"/>
</Office>
<Office Code="2A" OtherAttribute="6">
<Customer CustomerId="2010" CodeModifier="A"/>
</Office>
<Office Code="2C" OtherAttribute="6">
<Customer CustomerId="0011" CodeModifier="C"/>
</Office>