XSLT 对子子元素进行排序

Posted

技术标签:

【中文标题】XSLT 对子子元素进行排序【英文标题】:XSLT Sort on child subelements 【发布时间】:2021-08-12 11:29:00 【问题描述】:

我正在尝试输出整个 XML,但 EVENT 元素按 ID 排序。作为 XSLT 的新手,我认为我仍然会尝试一下,但经过多次尝试并阅读了其他示例以及如何指导后,我仍然无法获得我认为简单的工作。

<?xml version="1.0" encoding="UTF-8"?>
<PublishWCWORKORDEROUT xmlns="http://www.xcessteel.com/maxo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" creationDateTime="2021-05-10T08:23:18+00:00" transLanguage="EN" baseLanguage="EN" messageID="3116171.1620634998889850919" maxoVersion="7 6 20190514-1348 V7611-365" event="1">
  <WCWORKORDEROUTSet>
    <WORKORDER action="Replace">
      <ACTCATEGORY />
      <X_3857>1.1838832494481975E7</X_3857>
      <Y_3857>-2766476.1752903816</Y_3857>
      <SPEC>
        <ALNVALUE />
        <REFID xsi:nil="true" />
        <ASSETATTRID>ACCOUNT_NO</ASSETATTRID>
        <CHANGEBY>ADMIN</CHANGEBY>
      </SPEC>
      <SPEC>
        <ALNVALUE />
        <REFID xsi:nil="true" />
      </SPEC>
      <SPEC>
        <ALNVALUE />
        <REFID xsi:nil="true" />
        <ASSETATTRID>METER_LOCATION</ASSETATTRID>
      </SPEC>
      <EVENT>
        <ID>CCC333</ID>
        <WORKTYPE>UNPLANNED</WORKTYPE>
      </EVENT>
      <EVENT>
        <ID>AAA111</ID>
        <WORKTYPE>PLANNED</WORKTYPE>
      </EVENT>
      <EVENT>
        <ID>BBB222</ID>
        <WORKTYPE>SCHEDULED</WORKTYPE>
      </EVENT>
      <ASSIGNMENT>
        <AMCREW />
        <WPLABORID>209336</WPLABORID>
      </ASSIGNMENT>
      <WCWODETAILS>
        <REFID xsi:nil="true" />
        <CUSTOMERNAME />
        <WCREGION>SWR</WCREGION>
        <ID>96057400</ID>
      </WCWODETAILS>
    </WORKORDER>
  </WCWORKORDEROUTSet>
</PublishWCWORKORDEROUT>

我已尝试使用此 XSLT,但显然它不正确。

<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"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="/PublishWCWORKORDEROUT">
    <xsl:copy>
        <xsl:apply-templates select="EVENT">
            <xsl:sort select="ID"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

【问题讨论】:

【参考方案1】:

您必须声明命名空间 xmlns="http://www.xcessteel.com/maxo" 然后在匹配中使用该前缀,并且可以像这样进行排序:

2021-05-24 10:19 编辑:缺少属性 action="Replace"

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:maxo="http://www.xcessteel.com/maxo"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
  
  <!-- identity transform -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="maxo:WORKORDER">
    <xsl:copy>
      <!-- Following line was missing -->
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="maxo:EVENT[1]/preceding-sibling::*"/>
      <xsl:apply-templates select="maxo:EVENT">
        <xsl:sort select="maxo:ID"/>
      </xsl:apply-templates>
      <xsl:apply-templates select="maxo:EVENT[ position()=last()]/following-sibling::*"/>
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

作为替代方案,以下方法也可以:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:maxo="http://www.xcessteel.com/maxo"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
  
  <!-- identity transform -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="maxo:EVENT[not(preceding-sibling:: maxo:EVENT)]">
    <xsl:for-each select=".|following-sibling:: maxo:EVENT">
      <xsl:sort select="maxo:ID"/>
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:for-each>
    
  </xsl:template>
    
  <xsl:template match="maxo:EVENT[ preceding-sibling:: maxo:EVENT]"/>  
  
</xsl:stylesheet>

【讨论】:

非常感谢 Siebe 我真的很感激!它可以工作,只是结果输出中的元素缺少其属性 。怎么保留? 我编辑了答案。缺少一行来处理属性 哇,太棒了。谢谢西贝。我欠你一个人情。干杯!

以上是关于XSLT 对子子元素进行排序的主要内容,如果未能解决你的问题,请参考以下文章

如何获取具有相同名称的元素并根据 XSLT 中的子节点值对它们进行排序

XSLT 根据最大​​子节点对父节点进行排序

XSLT 按两个子属性对父对象进行排序

子元素初始化后,父组件对子 DOM 的操作导致 ExpressionChangedAfterItHasBeenCheckedError

XSLT 1.0 / 使用条件对每个结果进行排序

排序算法之快速排序