XSLT 根据子元素属性对父元素排序 [英] XSLT sort parent element based on child element attribute
问题描述
虽然这个问题已经被多次询问,就像
这个xml
<订单><订单类型="S"><Ref>ABC123</Ref><OrderedBy><债务人代码="13456"></债务人></OrderedBy><DeliveryMethod 代码="卡车"></DeliveryMethod><OrderLine line="1"><商品代码="ABC100400"></商品><数量>1</数量></订单行><OrderLine line="2"><Item code="XYZ490204" type="S" searchcode="XYZ490204"></Item><数量>2</数量></订单行><OrderLine line="3"><Item code="DEF1210847" type="S" searchcode="DEF1210847"></Item><数量>4</数量></订单行></订单><订单类型="S"><Ref>ABC123</Ref><OrderedBy><Debtor code="BLABLA" number="802416" type="C"></Debtor></OrderedBy><DeliveryMethod code="Barefoot"></DeliveryMethod><OrderLine line="1"><Item code="QQQ123456" type="S" searchcode="QQQ123456"></Item><数量>1</数量></订单行><OrderLine line="2"><商品代码="JJJ490204" type="S" searchcode="JJJ490204"></Item><数量>3</数量></订单行></订单></订单></root>
需要转换成这个xml:
<订单><订单类型="S"><Ref>ABC123</Ref><OrderedBy><债务人代码="13456"></债务人></OrderedBy><DeliveryMethod 代码="卡车"></DeliveryMethod><OrderLine line="1"><商品代码="ABC100400"></商品><数量>1</数量></订单行><OrderLine line="3"><商品代码="DEF1210847"></商品><数量>4</数量></订单行><OrderLine line="2"><商品代码="XYZ490204"></商品><数量>2</数量></订单行></订单><订单类型="S"><Ref>ABC123</Ref><OrderedBy><债务人代码="BLABLA"></债务人></OrderedBy><DeliveryMethod code="Barefoot"></DeliveryMethod><OrderLine line="2"><商品代码="JJJ490204"></商品><数量>3</数量></订单行><OrderLine line="1"><商品代码="QQQ123456"></商品><数量>1</数量></订单行></订单></订单></root>
我想要做的是对每个
根据子
并去除该孩子的一些属性.
元素进行排序;/@codeOrderLine
之外的所有其他元素都需要保持不变.请不要介意 xml 的非最佳结构,这是无法更改的.它可能需要复制,对于每个与排序结合的,像这样,但要好得多:
<xsl:output indent="yes"/><xsl:strip-space elements="*"/><xsl:template match="@* | node()"><xsl:copy><xsl:apply-templates select="@* | node()"/></xsl:copy></xsl:模板><xsl:template match="订单"><xsl:copy><xsl:apply-templates select="Order/OrderLine/Item|@*"><xsl:sort select="@code" data-type="text"/></xsl:apply-templates></xsl:copy></xsl:模板></xsl:stylesheet>
我要做的是对每个
的属性值排序
元素基于子
...
- /@code
如果要对 OrderLine
元素进行排序,则必须从其父 Order
的上下文中进行排序:
XSLT 1.0
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/><xsl:strip-space elements="*"/><!-- 身份变换--><xsl:template match="@*|node()"><xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy></xsl:模板><xsl:template match="订单"><xsl:copy><xsl:apply-templates select="@*"/><xsl:apply-templates select="*[not(self::OrderLine)]"/><xsl:apply-templates select="OrderLine"><xsl:sort select="Item/@code" data-type="text" order="ascending"/></xsl:apply-templates></xsl:copy></xsl:模板></xsl:stylesheet>
注意:由于空字符串先排序,您可以将模板缩短为:
<xsl:copy><xsl:apply-templates select="@*|node()"><xsl:sort select="Item/@code" data-type="text" order="ascending"/></xsl:apply-templates></xsl:copy></xsl:模板>
<块引用>
.. 并且还去除了那个孩子的一些属性.
我在你的样式表中没有看到.无论如何,只需添加另一个模板来匹配Item
.
Although this question has been asked multiples times like here and here before and the answers all seem to work for that particular question, I can't get it to work in my situation.
This xml
<root>
<Orders>
<Order type="S">
<Ref>ABC123</Ref>
<OrderedBy>
<Debtor code="13456"></Debtor>
</OrderedBy>
<DeliveryMethod code="Truck"></DeliveryMethod>
<OrderLine line="1">
<Item code="ABC100400"></Item>
<Quantity>1</Quantity>
</OrderLine>
<OrderLine line="2">
<Item code="XYZ490204" type="S" searchcode="XYZ490204"></Item>
<Quantity>2</Quantity>
</OrderLine>
<OrderLine line="3">
<Item code="DEF1210847" type="S" searchcode="DEF1210847"></Item>
<Quantity>4</Quantity>
</OrderLine>
</Order>
<Order type="S">
<Ref>ABC123</Ref>
<OrderedBy>
<Debtor code="BLABLA" number="802416" type="C"></Debtor>
</OrderedBy>
<DeliveryMethod code="Barefoot"></DeliveryMethod>
<OrderLine line="1">
<Item code="QQQ123456" type="S" searchcode="QQQ123456"></Item>
<Quantity>1</Quantity>
</OrderLine>
<OrderLine line="2">
<Item code="JJJ490204" type="S" searchcode="JJJ490204"></Item>
<Quantity>3</Quantity>
</OrderLine>
</Order>
</Orders>
</root>
needs to be transformed to this xml:
<root>
<Orders>
<Order type="S">
<Ref>ABC123</Ref>
<OrderedBy>
<Debtor code="13456"></Debtor>
</OrderedBy>
<DeliveryMethod code="Truck"></DeliveryMethod>
<OrderLine line="1">
<Item code="ABC100400"></Item>
<Quantity>1</Quantity>
</OrderLine>
<OrderLine line="3">
<Item code="DEF1210847"></Item>
<Quantity>4</Quantity>
</OrderLine>
<OrderLine line="2">
<Item code="XYZ490204"></Item>
<Quantity>2</Quantity>
</OrderLine>
</Order>
<Order type="S">
<Ref>ABC123</Ref>
<OrderedBy>
<Debtor code="BLABLA"></Debtor>
</OrderedBy>
<DeliveryMethod code="Barefoot"></DeliveryMethod>
<OrderLine line="2">
<Item code="JJJ490204"></Item>
<Quantity>3</Quantity>
</OrderLine>
<OrderLine line="1">
<Item code="QQQ123456"></Item>
<Quantity>1</Quantity>
</OrderLine>
</Order>
</Orders>
</root>
What I'm trying to do is for each <Order>
sort the <OrderLine>
elements based on the attributevalue of child <Item>/@code
and also strip some attributes of that child. All the other element outside of OrderLine
need to be left unchanged. Please don't mind the non-optimal structure of the xml, this can't be changed. It probably will take copy, for each combined with sort, like this, but much better:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Orders">
<xsl:copy>
<xsl:apply-templates select="Order/OrderLine/Item|@*">
<xsl:sort select="@code" data-type="text"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
What I'm trying to do is for each
<Order>
sort the<OrderLine>
elements based on the attributevalue of child<Item>/@code
...
If you want to sort the OrderLine
elements, you must do so from the context of their parent Order
:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Order">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*[not(self::OrderLine)]"/>
<xsl:apply-templates select="OrderLine">
<xsl:sort select="Item/@code" data-type="text" order="ascending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note: since empty strings sort first, you could shorten the template to:
<xsl:template match="Order">
<xsl:copy>
<xsl:apply-templates select="@*|node()">
<xsl:sort select="Item/@code" data-type="text" order="ascending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
.. and also strip some attributes of that child.
I didn't see that in your stylesheet. In any case, it's just a matter of adding another template to match Item
.
这篇关于XSLT 根据子元素属性对父元素排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!