如何使用 XSLT 1.0 对 xml 的多个嵌套元素组进行排序?
How to sort multiple nested element groups of xml with XSLT 1.0?
我找到了一个名为 XSLT sort by attribute value 的 SO post,它的 objective 与我的相似。我正在尝试使用 XSLT 1.0
按属性值对 xml 节点进行排序。但是当我尝试应用公认的解决方案时,我得到了意想不到的结果。
这是我的系统中的一些非常 stripped-down xml 的东西,我试图在其上实现 XSLT-based 排序。
<?xml version="1.0" encoding="UTF-8"?>
<mpcbom xmlns:bv="urn:BomViewXmlUtil" xmlns:msxsl="urn:schemas-microsoft-com:xslt" seriesid="Flatbed_A" seriesdesc="Flatbed A" modelid="FB2" modeldesc="Flatbed Aluminum 123" pricelistid="0">
<propDefn>
<prop seriesid="Flatbed_A" id="AddCharges" text="AddCharges" />
</propDefn>
<assembly seriesid="Flatbed_A" id="102B-1" name="Flatbed_B" qty="1" price="123" catid="Finish_unit">
<prop id="PriceOverride" val="False" />
<prop id="SuggestedPrice" val="54005" />
<prop id="TabSeqNum" val="0" src="Assembly" />
<operation seriesid="Flatbed_A" id="ALC-FOB" name="Client delivery" qty="1" price="0" catid="O_ABC123">
<prop id="HostOptionID" val="ALC-FOB" />
<prop id="ProcessTimeStd" val="0" />
<prop id="ProcessTimeXtra" val="0" />
</operation>
<assembly seriesid="Flatbed_A" id="102B-2" name="Unit_Offline" qty="1" price="0" catid="Unit_Offline">
<prop id="HostOptionID" val="" />
<prop id="ERP_RouteId" val="" />
<assembly seriesid="Flatbed_A" id="Step70" name="Step70" qty="1" price="0" catid="Step70">
<prop id="HostOptionID" val="Step70" />
<prop id="BOMUOM_From_BYOD" val="UN / EA" />
<operation seriesid="Flatbed_A" id="523-110" name="Washing" qty="1" price="0" catid="O_523_110">
<prop id="HostOptionID" val="523-110" />
<prop id="ProcessTimeStd" val="3.5" />
</operation>
<operation seriesid="Flatbed_A" id="523-120" name="Finish1" qty="1" price="0" catid="O_523_120">
<prop id="HostOptionID" val="523-120" />
<prop id="ProcessTimeStd" val="0.5" />
</operation>
<material seriesid="Flatbed_A" id="3UN5020000" name="Rubber1" qty="1" price="0" catid="Rear_Bumper_Option_Assy">
<prop id="Cost" val="124.9899768" />
<prop id="ExtCost" val="124.9899768" />
</material>
<material seriesid="Flatbed_A" id="3UN5990000" name="Round1" qty="1" price="0" catid="Doc_Holder_Assy">
<prop id="Cost" val="5.11" />
<prop id="ExtCost" val="5.11" />
</material>
</assembly>
<assembly seriesid="Flatbed_A" id="102B-3" name="ABC1" qty="1" price="0" catid="Assembled_Unit">
<prop id="CatID" val="Assembled_Unit" />
<prop id="HostOptionID" val="102B-3" />
<assembly seriesid="Flatbed_A" id="Step10" name="Step10" qty="1" price="0" catid="Step10">
<prop id="HostOptionID" val="Step10" />
<prop id="BOMUOM_From_BYOD" val="UN / EA" />
<operation seriesid="Flatbed_A" id="510-110" name="Assemblage 1" qty="1" price="0" catid="O_510_110">
<prop id="HostOptionID" val="510-110" />
<prop id="ProcessTimeStd" val="13.5" />
</operation>
<material seriesid="Flatbed_A" id="XYZ123" name="Front rail" qty="1" price="0" catid="Front_Rail_assy">
<prop id="Cost" val="80.679768" />
<prop id="ExtCost" val="80.679768" />
</material>
<material seriesid="Flatbed_A" id="FB2C53XXXA" name="53ft 2 axles Flatbed" qty="1" price="0" catid="Structure_Assy">
<prop id="Cost" val="12901.27129" />
<prop id="ExtCost" val="12901.27129" />
</material>
<material seriesid="Flatbed_A" id="ABC123" name="Front rail" qty="1" price="0" catid="Front_Rail_assy">
<prop id="Cost" val="80.679768" />
<prop id="ExtCost" val="80.679768" />
</material>
</assembly>
<assembly seriesid="Flatbed_A" id="Step20" name="Step20" qty="1" price="0" catid="Step20">
<prop id="HostOptionID" val="Step20" />
<prop id="BOMUOM_From_BYOD" val="UN / EA" />
<operation seriesid="Flatbed_A" id="510-120" name="Assemblage 2" qty="1" price="0" catid="O_510_120">
<prop id="HostOptionID" val="510-120" />
<prop id="ProcessTimeStd" val="14" />
</operation>
<material seriesid="Flatbed_A" id="DEF123" name="PLANCHER 53" qty="1" price="0" catid="FloorAlu_Assy">
<prop id="Cost" val="3629.53568" />
<prop id="ExtCost" val="3629.53568" />
</material>
<material seriesid="Flatbed_A" id="STU123" name="6-4in" qty="1" price="0" catid="Rear_Bumper_Assy">
<prop id="Cost" val="773.383414" />
<prop id="ExtCost" val="773.383414" />
</material>
<material seriesid="Flatbed_A" id="ABC123" name="6-4in" qty="1" price="0" catid="Rear_Bumper_Assy">
<prop id="Cost" val="773.383414" />
<prop id="ExtCost" val="773.383414" />
</material>
</assembly>
</assembly>
</assembly>
</assembly>
</mpcbom>
这是我的基本 XSLT,它完全符合我的需要,减去排序:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes" indent="no" version="1.0" standalone="yes" />
<xsl:variable name="lowercase">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:variable name="uppercase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="propDefn" />
<xsl:template match="material|operation">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="prop">
<xsl:sort select="translate(@id, $uppercase, $lowercase)" />
</xsl:apply-templates>
<xsl:apply-templates select="*[not(self::prop)]" />
</xsl:copy>
</xsl:template>
<xsl:template match="@rid" />
<xsl:template match="material/@name|material/@name|operation/@name" />
<xsl:template match="@id|@catid">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="translate(., $uppercase, $lowercase)" />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
这里是上面转换的xml结果:
<?xml version="1.0" encoding="UTF-8"?>
<mpcbom xmlns:bv="urn:BomViewXmlUtil" xmlns:msxsl="urn:schemas-microsoft-com:xslt" seriesid="Flatbed_A" seriesdesc="Flatbed A" modelid="FB2" modeldesc="Flatbed Aluminum 123" pricelistid="0">
<assembly seriesid="Flatbed_A" id="102b-1" name="Flatbed_B" qty="1" price="123" catid="finish_unit">
<prop id="priceoverride" val="False" />
<prop id="suggestedprice" val="54005" />
<prop id="tabseqnum" val="0" src="Assembly" />
<operation seriesid="Flatbed_A" id="alc-fob" qty="1" price="0" catid="o_abc123">
<prop id="hostoptionid" val="ALC-FOB" />
<prop id="processtimestd" val="0" />
<prop id="processtimextra" val="0" />
</operation>
<assembly seriesid="Flatbed_A" id="102b-2" name="Unit_Offline" qty="1" price="0" catid="unit_offline">
<prop id="hostoptionid" val="" />
<prop id="erp_routeid" val="" />
<assembly seriesid="Flatbed_A" id="step70" name="Step70" qty="1" price="0" catid="step70">
<prop id="hostoptionid" val="Step70" />
<prop id="bomuom_from_byod" val="UN / EA" />
<operation seriesid="Flatbed_A" id="523-110" qty="1" price="0" catid="o_523_110">
<prop id="hostoptionid" val="523-110" />
<prop id="processtimestd" val="3.5" />
</operation>
<operation seriesid="Flatbed_A" id="523-120" qty="1" price="0" catid="o_523_120">
<prop id="hostoptionid" val="523-120" />
<prop id="processtimestd" val="0.5" />
</operation>
<material seriesid="Flatbed_A" id="3un5020000" qty="1" price="0" catid="rear_bumper_option_assy">
<prop id="cost" val="124.9899768" />
<prop id="extcost" val="124.9899768" />
</material>
<material seriesid="Flatbed_A" id="3un5990000" qty="1" price="0" catid="doc_holder_assy">
<prop id="cost" val="5.11" />
<prop id="extcost" val="5.11" />
</material>
</assembly>
<assembly seriesid="Flatbed_A" id="102b-3" name="ABC1" qty="1" price="0" catid="assembled_unit">
<prop id="catid" val="Assembled_Unit" />
<prop id="hostoptionid" val="102B-3" />
<assembly seriesid="Flatbed_A" id="step10" name="Step10" qty="1" price="0" catid="step10">
<prop id="hostoptionid" val="Step10" />
<prop id="bomuom_from_byod" val="UN / EA" />
<operation seriesid="Flatbed_A" id="510-110" qty="1" price="0" catid="o_510_110">
<prop id="hostoptionid" val="510-110" />
<prop id="processtimestd" val="13.5" />
</operation>
<material seriesid="Flatbed_A" id="xyz123" qty="1" price="0" catid="front_rail_assy">
<prop id="cost" val="80.679768" />
<prop id="extcost" val="80.679768" />
</material>
<material seriesid="Flatbed_A" id="fb2c53xxxa" qty="1" price="0" catid="structure_assy">
<prop id="cost" val="12901.27129" />
<prop id="extcost" val="12901.27129" />
</material>
<material seriesid="Flatbed_A" id="abc123" qty="1" price="0" catid="front_rail_assy">
<prop id="cost" val="80.679768" />
<prop id="extcost" val="80.679768" />
</material>
</assembly>
<assembly seriesid="Flatbed_A" id="step20" name="Step20" qty="1" price="0" catid="step20">
<prop id="hostoptionid" val="Step20" />
<prop id="bomuom_from_byod" val="UN / EA" />
<operation seriesid="Flatbed_A" id="510-120" qty="1" price="0" catid="o_510_120">
<prop id="hostoptionid" val="510-120" />
<prop id="processtimestd" val="14" />
</operation>
<material seriesid="Flatbed_A" id="def123" qty="1" price="0" catid="flooralu_assy">
<prop id="cost" val="3629.53568" />
<prop id="extcost" val="3629.53568" />
</material>
<material seriesid="Flatbed_A" id="stu123" qty="1" price="0" catid="rear_bumper_assy">
<prop id="cost" val="773.383414" />
<prop id="extcost" val="773.383414" />
</material>
<material seriesid="Flatbed_A" id="abc123" qty="1" price="0" catid="rear_bumper_assy">
<prop id="cost" val="773.383414" />
<prop id="extcost" val="773.383414" />
</material>
</assembly>
</assembly>
</assembly>
</assembly>
</mpcbom>
到目前为止一切顺利,但同样,尚未尝试进行排序。现在这里是与上面相同的 XSLT,但添加了我的排序尝试:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes" indent="no" version="1.0" standalone="yes" />
<xsl:variable name="lowercase">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:variable name="uppercase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="propDefn" />
<xsl:template match="material|operation">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="prop">
<xsl:sort select="translate(@id, $uppercase, $lowercase)" />
</xsl:apply-templates>
<xsl:apply-templates select="*[not(self::prop)]" />
</xsl:copy>
</xsl:template>
<xsl:template match="assembly">
<xsl:copy>
<xsl:apply-templates select="assembly">
<xsl:sort select="material/@id"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="@rid" />
<xsl:template match="material/@name|material/@name|operation/@name" />
<xsl:template match="@id|@catid">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="translate(., $uppercase, $lowercase)" />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
为清楚起见,这是我添加的部分(尝试排序):
<xsl:template match="assembly">
<xsl:copy>
<xsl:apply-templates select="assembly">
<xsl:sort select="material/@id"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
这是转换的灾难性结果(与上面相同的 xml 来源):
<?xml version="1.0" encoding="UTF-8"?>
<mpcbom xmlns:bv="urn:BomViewXmlUtil" xmlns:msxsl="urn:schemas-microsoft-com:xslt" seriesid="Flatbed_A" seriesdesc="Flatbed A" modelid="FB2" modeldesc="Flatbed Aluminum 123" pricelistid="0">
<assembly>
<assembly>
<assembly>
<assembly />
<assembly />
</assembly>
<assembly />
</assembly>
</assembly>
</mpcbom>
显然我是 XSLT 的新手...但这就是我想要实现的目标:每当 <assembly>
节点内有 <material>
个节点时,我想要所有 <material>
个节点按其 id
属性以字母数字方式排序。比如从源码中取这组节点xml:
<material seriesid="Flatbed_A" id="XYZ123" name="Front rail" qty="1" price="0" catid="Front_Rail_assy">
<prop id="Cost" val="80.679768" />
<prop id="ExtCost" val="80.679768" />
</material>
<material seriesid="Flatbed_A" id="FB2C53XXXA" name="53ft 2 axles Flatbed" qty="1" price="0" catid="Structure_Assy">
<prop id="Cost" val="12901.27129" />
<prop id="ExtCost" val="12901.27129" />
</material>
<material seriesid="Flatbed_A" id="ABC123" name="Front rail" qty="1" price="0" catid="Front_Rail_assy">
<prop id="Cost" val="80.679768" />
<prop id="ExtCost" val="80.679768" />
</material>
注意 3 个 <material>
节点的 id
:XYZ123
、FB2C53XXXA
、ABC123
。我需要按 id
排序的那些,以便转换后的 xml(仅针对该部分)看起来像这样:
<material seriesid="Flatbed_A" id="ABC123" name="Front rail" qty="1" price="0" catid="Front_Rail_assy">
<prop id="Cost" val="80.679768" />
<prop id="ExtCost" val="80.679768" />
</material>
<material seriesid="Flatbed_A" id="FB2C53XXXA" name="53ft 2 axles Flatbed" qty="1" price="0" catid="Structure_Assy">
<prop id="Cost" val="12901.27129" />
<prop id="ExtCost" val="12901.27129" />
</material>
<material seriesid="Flatbed_A" id="XYZ123" name="Front rail" qty="1" price="0" catid="Front_Rail_assy">
<prop id="Cost" val="80.679768" />
<prop id="ExtCost" val="80.679768" />
</material>
第二组 <material>
节点也是如此。原文:
<material seriesid="Flatbed_A" id="DEF123" name="PLANCHER 53" qty="1" price="0" catid="FloorAlu_Assy">
<prop id="Cost" val="3629.53568" />
<prop id="ExtCost" val="3629.53568" />
</material>
<material seriesid="Flatbed_A" id="STU123" name="6-4in" qty="1" price="0" catid="Rear_Bumper_Assy">
<prop id="Cost" val="773.383414" />
<prop id="ExtCost" val="773.383414" />
</material>
<material seriesid="Flatbed_A" id="ABC123" name="6-4in" qty="1" price="0" catid="Rear_Bumper_Assy">
<prop id="Cost" val="773.383414" />
<prop id="ExtCost" val="773.383414" />
</material>
需要排序,转换后:
<material seriesid="Flatbed_A" id="ABC123" name="6-4in" qty="1" price="0" catid="Rear_Bumper_Assy">
<prop id="Cost" val="773.383414" />
<prop id="ExtCost" val="773.383414" />
</material>
<material seriesid="Flatbed_A" id="DEF123" name="PLANCHER 53" qty="1" price="0" catid="FloorAlu_Assy">
<prop id="Cost" val="3629.53568" />
<prop id="ExtCost" val="3629.53568" />
</material>
<material seriesid="Flatbed_A" id="STU123" name="6-4in" qty="1" price="0" catid="Rear_Bumper_Assy">
<prop id="Cost" val="773.383414" />
<prop id="ExtCost" val="773.383414" />
</material>
怎么做到的?
您添加的模板的问题在于它仅将模板应用于子 assembly
元素 - 因此删除了父 assembly
可能具有的所有其他子节点(及其后代)。
另一件事是您正在对 assembly
元素进行排序 - 但随后您解释说您实际上想要对 material
元素进行排序。
现在,由于要排序的 material
个元素还有其他兄弟元素,例如 prop
、operation
和 assembly
,这些兄弟元素也有一个id
属性,你基本上有两个选择:
对所有模板应用模板,但按只有 material
具有的节点排序:
<xsl:template match="assembly">
<xsl:copy>
<xsl:apply-templates select="@*|node()">
<xsl:sort select="@id[parent::material]"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
但是,这将始终将 material
组放在末尾,
即使原版中没有。
分别对每个子节点(或子节点组)应用模板
节点)并仅对 material
元素组进行排序 - 例如
<xsl:template match="assembly">
<xsl:copy>
<xsl:apply-templates select="@* | prop | operation | assembly"/>
<xsl:apply-templates select="material">
<xsl:sort select="@id"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
在这里您可以使用单独的
xsl:apply-templates
每组说明,按照你的顺序
想要它们。
我找到了一个名为 XSLT sort by attribute value 的 SO post,它的 objective 与我的相似。我正在尝试使用 XSLT 1.0
按属性值对 xml 节点进行排序。但是当我尝试应用公认的解决方案时,我得到了意想不到的结果。
这是我的系统中的一些非常 stripped-down xml 的东西,我试图在其上实现 XSLT-based 排序。
<?xml version="1.0" encoding="UTF-8"?>
<mpcbom xmlns:bv="urn:BomViewXmlUtil" xmlns:msxsl="urn:schemas-microsoft-com:xslt" seriesid="Flatbed_A" seriesdesc="Flatbed A" modelid="FB2" modeldesc="Flatbed Aluminum 123" pricelistid="0">
<propDefn>
<prop seriesid="Flatbed_A" id="AddCharges" text="AddCharges" />
</propDefn>
<assembly seriesid="Flatbed_A" id="102B-1" name="Flatbed_B" qty="1" price="123" catid="Finish_unit">
<prop id="PriceOverride" val="False" />
<prop id="SuggestedPrice" val="54005" />
<prop id="TabSeqNum" val="0" src="Assembly" />
<operation seriesid="Flatbed_A" id="ALC-FOB" name="Client delivery" qty="1" price="0" catid="O_ABC123">
<prop id="HostOptionID" val="ALC-FOB" />
<prop id="ProcessTimeStd" val="0" />
<prop id="ProcessTimeXtra" val="0" />
</operation>
<assembly seriesid="Flatbed_A" id="102B-2" name="Unit_Offline" qty="1" price="0" catid="Unit_Offline">
<prop id="HostOptionID" val="" />
<prop id="ERP_RouteId" val="" />
<assembly seriesid="Flatbed_A" id="Step70" name="Step70" qty="1" price="0" catid="Step70">
<prop id="HostOptionID" val="Step70" />
<prop id="BOMUOM_From_BYOD" val="UN / EA" />
<operation seriesid="Flatbed_A" id="523-110" name="Washing" qty="1" price="0" catid="O_523_110">
<prop id="HostOptionID" val="523-110" />
<prop id="ProcessTimeStd" val="3.5" />
</operation>
<operation seriesid="Flatbed_A" id="523-120" name="Finish1" qty="1" price="0" catid="O_523_120">
<prop id="HostOptionID" val="523-120" />
<prop id="ProcessTimeStd" val="0.5" />
</operation>
<material seriesid="Flatbed_A" id="3UN5020000" name="Rubber1" qty="1" price="0" catid="Rear_Bumper_Option_Assy">
<prop id="Cost" val="124.9899768" />
<prop id="ExtCost" val="124.9899768" />
</material>
<material seriesid="Flatbed_A" id="3UN5990000" name="Round1" qty="1" price="0" catid="Doc_Holder_Assy">
<prop id="Cost" val="5.11" />
<prop id="ExtCost" val="5.11" />
</material>
</assembly>
<assembly seriesid="Flatbed_A" id="102B-3" name="ABC1" qty="1" price="0" catid="Assembled_Unit">
<prop id="CatID" val="Assembled_Unit" />
<prop id="HostOptionID" val="102B-3" />
<assembly seriesid="Flatbed_A" id="Step10" name="Step10" qty="1" price="0" catid="Step10">
<prop id="HostOptionID" val="Step10" />
<prop id="BOMUOM_From_BYOD" val="UN / EA" />
<operation seriesid="Flatbed_A" id="510-110" name="Assemblage 1" qty="1" price="0" catid="O_510_110">
<prop id="HostOptionID" val="510-110" />
<prop id="ProcessTimeStd" val="13.5" />
</operation>
<material seriesid="Flatbed_A" id="XYZ123" name="Front rail" qty="1" price="0" catid="Front_Rail_assy">
<prop id="Cost" val="80.679768" />
<prop id="ExtCost" val="80.679768" />
</material>
<material seriesid="Flatbed_A" id="FB2C53XXXA" name="53ft 2 axles Flatbed" qty="1" price="0" catid="Structure_Assy">
<prop id="Cost" val="12901.27129" />
<prop id="ExtCost" val="12901.27129" />
</material>
<material seriesid="Flatbed_A" id="ABC123" name="Front rail" qty="1" price="0" catid="Front_Rail_assy">
<prop id="Cost" val="80.679768" />
<prop id="ExtCost" val="80.679768" />
</material>
</assembly>
<assembly seriesid="Flatbed_A" id="Step20" name="Step20" qty="1" price="0" catid="Step20">
<prop id="HostOptionID" val="Step20" />
<prop id="BOMUOM_From_BYOD" val="UN / EA" />
<operation seriesid="Flatbed_A" id="510-120" name="Assemblage 2" qty="1" price="0" catid="O_510_120">
<prop id="HostOptionID" val="510-120" />
<prop id="ProcessTimeStd" val="14" />
</operation>
<material seriesid="Flatbed_A" id="DEF123" name="PLANCHER 53" qty="1" price="0" catid="FloorAlu_Assy">
<prop id="Cost" val="3629.53568" />
<prop id="ExtCost" val="3629.53568" />
</material>
<material seriesid="Flatbed_A" id="STU123" name="6-4in" qty="1" price="0" catid="Rear_Bumper_Assy">
<prop id="Cost" val="773.383414" />
<prop id="ExtCost" val="773.383414" />
</material>
<material seriesid="Flatbed_A" id="ABC123" name="6-4in" qty="1" price="0" catid="Rear_Bumper_Assy">
<prop id="Cost" val="773.383414" />
<prop id="ExtCost" val="773.383414" />
</material>
</assembly>
</assembly>
</assembly>
</assembly>
</mpcbom>
这是我的基本 XSLT,它完全符合我的需要,减去排序:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes" indent="no" version="1.0" standalone="yes" />
<xsl:variable name="lowercase">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:variable name="uppercase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="propDefn" />
<xsl:template match="material|operation">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="prop">
<xsl:sort select="translate(@id, $uppercase, $lowercase)" />
</xsl:apply-templates>
<xsl:apply-templates select="*[not(self::prop)]" />
</xsl:copy>
</xsl:template>
<xsl:template match="@rid" />
<xsl:template match="material/@name|material/@name|operation/@name" />
<xsl:template match="@id|@catid">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="translate(., $uppercase, $lowercase)" />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
这里是上面转换的xml结果:
<?xml version="1.0" encoding="UTF-8"?>
<mpcbom xmlns:bv="urn:BomViewXmlUtil" xmlns:msxsl="urn:schemas-microsoft-com:xslt" seriesid="Flatbed_A" seriesdesc="Flatbed A" modelid="FB2" modeldesc="Flatbed Aluminum 123" pricelistid="0">
<assembly seriesid="Flatbed_A" id="102b-1" name="Flatbed_B" qty="1" price="123" catid="finish_unit">
<prop id="priceoverride" val="False" />
<prop id="suggestedprice" val="54005" />
<prop id="tabseqnum" val="0" src="Assembly" />
<operation seriesid="Flatbed_A" id="alc-fob" qty="1" price="0" catid="o_abc123">
<prop id="hostoptionid" val="ALC-FOB" />
<prop id="processtimestd" val="0" />
<prop id="processtimextra" val="0" />
</operation>
<assembly seriesid="Flatbed_A" id="102b-2" name="Unit_Offline" qty="1" price="0" catid="unit_offline">
<prop id="hostoptionid" val="" />
<prop id="erp_routeid" val="" />
<assembly seriesid="Flatbed_A" id="step70" name="Step70" qty="1" price="0" catid="step70">
<prop id="hostoptionid" val="Step70" />
<prop id="bomuom_from_byod" val="UN / EA" />
<operation seriesid="Flatbed_A" id="523-110" qty="1" price="0" catid="o_523_110">
<prop id="hostoptionid" val="523-110" />
<prop id="processtimestd" val="3.5" />
</operation>
<operation seriesid="Flatbed_A" id="523-120" qty="1" price="0" catid="o_523_120">
<prop id="hostoptionid" val="523-120" />
<prop id="processtimestd" val="0.5" />
</operation>
<material seriesid="Flatbed_A" id="3un5020000" qty="1" price="0" catid="rear_bumper_option_assy">
<prop id="cost" val="124.9899768" />
<prop id="extcost" val="124.9899768" />
</material>
<material seriesid="Flatbed_A" id="3un5990000" qty="1" price="0" catid="doc_holder_assy">
<prop id="cost" val="5.11" />
<prop id="extcost" val="5.11" />
</material>
</assembly>
<assembly seriesid="Flatbed_A" id="102b-3" name="ABC1" qty="1" price="0" catid="assembled_unit">
<prop id="catid" val="Assembled_Unit" />
<prop id="hostoptionid" val="102B-3" />
<assembly seriesid="Flatbed_A" id="step10" name="Step10" qty="1" price="0" catid="step10">
<prop id="hostoptionid" val="Step10" />
<prop id="bomuom_from_byod" val="UN / EA" />
<operation seriesid="Flatbed_A" id="510-110" qty="1" price="0" catid="o_510_110">
<prop id="hostoptionid" val="510-110" />
<prop id="processtimestd" val="13.5" />
</operation>
<material seriesid="Flatbed_A" id="xyz123" qty="1" price="0" catid="front_rail_assy">
<prop id="cost" val="80.679768" />
<prop id="extcost" val="80.679768" />
</material>
<material seriesid="Flatbed_A" id="fb2c53xxxa" qty="1" price="0" catid="structure_assy">
<prop id="cost" val="12901.27129" />
<prop id="extcost" val="12901.27129" />
</material>
<material seriesid="Flatbed_A" id="abc123" qty="1" price="0" catid="front_rail_assy">
<prop id="cost" val="80.679768" />
<prop id="extcost" val="80.679768" />
</material>
</assembly>
<assembly seriesid="Flatbed_A" id="step20" name="Step20" qty="1" price="0" catid="step20">
<prop id="hostoptionid" val="Step20" />
<prop id="bomuom_from_byod" val="UN / EA" />
<operation seriesid="Flatbed_A" id="510-120" qty="1" price="0" catid="o_510_120">
<prop id="hostoptionid" val="510-120" />
<prop id="processtimestd" val="14" />
</operation>
<material seriesid="Flatbed_A" id="def123" qty="1" price="0" catid="flooralu_assy">
<prop id="cost" val="3629.53568" />
<prop id="extcost" val="3629.53568" />
</material>
<material seriesid="Flatbed_A" id="stu123" qty="1" price="0" catid="rear_bumper_assy">
<prop id="cost" val="773.383414" />
<prop id="extcost" val="773.383414" />
</material>
<material seriesid="Flatbed_A" id="abc123" qty="1" price="0" catid="rear_bumper_assy">
<prop id="cost" val="773.383414" />
<prop id="extcost" val="773.383414" />
</material>
</assembly>
</assembly>
</assembly>
</assembly>
</mpcbom>
到目前为止一切顺利,但同样,尚未尝试进行排序。现在这里是与上面相同的 XSLT,但添加了我的排序尝试:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes" indent="no" version="1.0" standalone="yes" />
<xsl:variable name="lowercase">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:variable name="uppercase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="propDefn" />
<xsl:template match="material|operation">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="prop">
<xsl:sort select="translate(@id, $uppercase, $lowercase)" />
</xsl:apply-templates>
<xsl:apply-templates select="*[not(self::prop)]" />
</xsl:copy>
</xsl:template>
<xsl:template match="assembly">
<xsl:copy>
<xsl:apply-templates select="assembly">
<xsl:sort select="material/@id"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="@rid" />
<xsl:template match="material/@name|material/@name|operation/@name" />
<xsl:template match="@id|@catid">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="translate(., $uppercase, $lowercase)" />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
为清楚起见,这是我添加的部分(尝试排序):
<xsl:template match="assembly">
<xsl:copy>
<xsl:apply-templates select="assembly">
<xsl:sort select="material/@id"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
这是转换的灾难性结果(与上面相同的 xml 来源):
<?xml version="1.0" encoding="UTF-8"?>
<mpcbom xmlns:bv="urn:BomViewXmlUtil" xmlns:msxsl="urn:schemas-microsoft-com:xslt" seriesid="Flatbed_A" seriesdesc="Flatbed A" modelid="FB2" modeldesc="Flatbed Aluminum 123" pricelistid="0">
<assembly>
<assembly>
<assembly>
<assembly />
<assembly />
</assembly>
<assembly />
</assembly>
</assembly>
</mpcbom>
显然我是 XSLT 的新手...但这就是我想要实现的目标:每当 <assembly>
节点内有 <material>
个节点时,我想要所有 <material>
个节点按其 id
属性以字母数字方式排序。比如从源码中取这组节点xml:
<material seriesid="Flatbed_A" id="XYZ123" name="Front rail" qty="1" price="0" catid="Front_Rail_assy">
<prop id="Cost" val="80.679768" />
<prop id="ExtCost" val="80.679768" />
</material>
<material seriesid="Flatbed_A" id="FB2C53XXXA" name="53ft 2 axles Flatbed" qty="1" price="0" catid="Structure_Assy">
<prop id="Cost" val="12901.27129" />
<prop id="ExtCost" val="12901.27129" />
</material>
<material seriesid="Flatbed_A" id="ABC123" name="Front rail" qty="1" price="0" catid="Front_Rail_assy">
<prop id="Cost" val="80.679768" />
<prop id="ExtCost" val="80.679768" />
</material>
注意 3 个 <material>
节点的 id
:XYZ123
、FB2C53XXXA
、ABC123
。我需要按 id
排序的那些,以便转换后的 xml(仅针对该部分)看起来像这样:
<material seriesid="Flatbed_A" id="ABC123" name="Front rail" qty="1" price="0" catid="Front_Rail_assy">
<prop id="Cost" val="80.679768" />
<prop id="ExtCost" val="80.679768" />
</material>
<material seriesid="Flatbed_A" id="FB2C53XXXA" name="53ft 2 axles Flatbed" qty="1" price="0" catid="Structure_Assy">
<prop id="Cost" val="12901.27129" />
<prop id="ExtCost" val="12901.27129" />
</material>
<material seriesid="Flatbed_A" id="XYZ123" name="Front rail" qty="1" price="0" catid="Front_Rail_assy">
<prop id="Cost" val="80.679768" />
<prop id="ExtCost" val="80.679768" />
</material>
第二组 <material>
节点也是如此。原文:
<material seriesid="Flatbed_A" id="DEF123" name="PLANCHER 53" qty="1" price="0" catid="FloorAlu_Assy">
<prop id="Cost" val="3629.53568" />
<prop id="ExtCost" val="3629.53568" />
</material>
<material seriesid="Flatbed_A" id="STU123" name="6-4in" qty="1" price="0" catid="Rear_Bumper_Assy">
<prop id="Cost" val="773.383414" />
<prop id="ExtCost" val="773.383414" />
</material>
<material seriesid="Flatbed_A" id="ABC123" name="6-4in" qty="1" price="0" catid="Rear_Bumper_Assy">
<prop id="Cost" val="773.383414" />
<prop id="ExtCost" val="773.383414" />
</material>
需要排序,转换后:
<material seriesid="Flatbed_A" id="ABC123" name="6-4in" qty="1" price="0" catid="Rear_Bumper_Assy">
<prop id="Cost" val="773.383414" />
<prop id="ExtCost" val="773.383414" />
</material>
<material seriesid="Flatbed_A" id="DEF123" name="PLANCHER 53" qty="1" price="0" catid="FloorAlu_Assy">
<prop id="Cost" val="3629.53568" />
<prop id="ExtCost" val="3629.53568" />
</material>
<material seriesid="Flatbed_A" id="STU123" name="6-4in" qty="1" price="0" catid="Rear_Bumper_Assy">
<prop id="Cost" val="773.383414" />
<prop id="ExtCost" val="773.383414" />
</material>
怎么做到的?
您添加的模板的问题在于它仅将模板应用于子 assembly
元素 - 因此删除了父 assembly
可能具有的所有其他子节点(及其后代)。
另一件事是您正在对 assembly
元素进行排序 - 但随后您解释说您实际上想要对 material
元素进行排序。
现在,由于要排序的 material
个元素还有其他兄弟元素,例如 prop
、operation
和 assembly
,这些兄弟元素也有一个id
属性,你基本上有两个选择:
对所有模板应用模板,但按只有
material
具有的节点排序:<xsl:template match="assembly"> <xsl:copy> <xsl:apply-templates select="@*|node()"> <xsl:sort select="@id[parent::material]"/> </xsl:apply-templates> </xsl:copy> </xsl:template>
但是,这将始终将
material
组放在末尾, 即使原版中没有。分别对每个子节点(或子节点组)应用模板 节点)并仅对
material
元素组进行排序 - 例如<xsl:template match="assembly"> <xsl:copy> <xsl:apply-templates select="@* | prop | operation | assembly"/> <xsl:apply-templates select="material"> <xsl:sort select="@id"/> </xsl:apply-templates> </xsl:copy> </xsl:template>
在这里您可以使用单独的
xsl:apply-templates
每组说明,按照你的顺序 想要它们。