XSLT 根据子元素属性对父元素排序 [英] XSLT sort parent element based on child element attribute

查看:36
本文介绍了XSLT 根据子元素属性对父元素排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

虽然这个问题已经被多次询问,就像此处 和 这里 之前和答案似乎都适用那个特定的问题,我无法让它在我的情况下工作.

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

我想要做的是对每个 根据子 的属性值对 元素进行排序;/@code 并去除该孩子的一些属性.OrderLine 之外的所有其他元素都需要保持不变.请不要介意 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆