【问题标题】:Missing some child nodes after sorting with `<xsl:apply-templates>`使用 `<xsl:apply-templates>` 排序后缺少一些子节点
【发布时间】:2021-03-15 08:26:58
【问题描述】:

我正在尝试根据字段 start_date 对子节点进行排序。在下面的 XML 节点 &lt;employment_information&gt; 中有两个子节点 &lt;job_information&gt;,start_date 需要升序。

经过大量搜索和尝试,我的排序工作正常,但我遇到的问题是&lt;employment_information&gt; 中的其他字段消失了。节点&lt;job_information&gt; 的顺序正确,但其他字段已消失。

我的 XML:

<queryCompoundEmployeeResponse>
  <CompoundEmployee period_start="2020-09-30" period_end="2020-12-03">
    <id>347</id>
    <type>CompoundEmployee</type>
    <swHire>Y</swHire>
    <swRehire>N</swRehire>
    <swRetire>N</swRetire>
    <person>
      <action>NO CHANGE</action>
      <country_of_birth>NLD</country_of_birth>
      <created_by>admin_nm</created_by>
      <created_on_timestamp>2018-05-02T14:03:25.000Z</created_on_timestamp>
      <person_id>347</person_id>
      <person_id_external>10160</person_id_external>
      <place_of_birth>aaa</place_of_birth>
      <employment_information>
        <action>NO CHANGE</action>
        <assignment_class>ST</assignment_class>
        <created_by>admin_nm</created_by>
        <created_on_timestamp>2018-05-02T14:03:25.000Z</created_on_timestamp>
        <direct_reports>12</direct_reports>
        <employment_id>347</employment_id>
        <hiringNotCompleted>false</hiringNotCompleted>
        <isContingentWorker>false</isContingentWorker>
        <jobNumber>1</jobNumber>
        <last_modified_by>aaa</last_modified_by>
        <last_modified_on>2019-09-05T10:38:50.000Z</last_modified_on>
        <originalStartDate>1992-05-01</originalStartDate>
        <serviceDate>1992-05-01</serviceDate>
        <start_date>1992-05-01</start_date>
        <user_id>10160</user_id>
        <job_information>
          <action>CHANGE</action>
          <shift_factor>0.0</shift_factor>
          <shift_rate>0.0</shift_rate>
          <standard_hours>38.0</standard_hours>
          <start_date>2020-10-10</start_date>
          <time_recording_admissibility_code>NL</time_recording_admissibility_code>
          <time_recording_profile_code>NL</time_recording_profile_code>
          <time_recording_variant>DURATION</time_recording_variant>
          <time_type_profile_code>NL20+/CI+</time_type_profile_code>
          <timezone>Europe/Amsterdam</timezone>
          <workingDaysPerWeek>5.0</workingDaysPerWeek>
          <workschedule_code>DUMMY</workschedule_code>
        </job_information>
        <job_information>
          <shift_factor>0.0</shift_factor>
          <shift_rate>0.0</shift_rate>
          <standard_hours>0.0</standard_hours>
          <start_date>2020-10-01</start_date>
          <timezone>Europe/Amsterdam</timezone>
          <workingDaysPerWeek>0.0</workingDaysPerWeek>
        </job_information>
        <job_event_information>
          <action>INSERT</action>
          <created_on_timestamp>2020-08-01T20:00:48.000Z</created_on_timestamp>
          <event>5</event>
          <event_date>2020-08-01</event_date>
          <event_reason>DATACHG</event_reason>
          <seq_number>1</seq_number>
        </job_event_information>
      </employment_information>
    </person>
    <execution_timestamp>2020-08-17T14:00:48.000Z</execution_timestamp>
    <version_id>2005P0</version_id>
  </CompoundEmployee>
</queryCompoundEmployeeResponse>

我使用的 XSL 是这样的:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" />

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

  <xsl:template match="queryCompoundEmployeeResponse/CompoundEmployee/person/employment_information">
    <xsl:copy>
      <xsl:apply-templates select="job_information">
        <!--  concat year, month, day -->
        <xsl:sort select="concat(
           substring(start_date, 1, 4),
           substring(start_date, 6, 2),
           substring(start_date, 9, 2)
        )" order="ascending" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

结果是这样的(摘录)

如您所见,排序没问题,但来自就业信息的其他孩子已经走了。 我如何才能保留它们?我错过了什么?

<employment_information>
  <job_information>
    <shift_factor>0.0</shift_factor>
    <shift_rate>0.0</shift_rate>
    <standard_hours>0.0</standard_hours>
    <start_date>2020-10-01</start_date>
    <timezone>Europe/Amsterdam</timezone>
    <workingDaysPerWeek>0.0</workingDaysPerWeek>
  </job_information>
  <job_information>
    <action>CHANGE</action>
    <shift_factor>0.0</shift_factor>
    <shift_rate>0.0</shift_rate>
    <standard_hours>38.0</standard_hours>
    <start_date>2020-10-10</start_date>
    <time_recording_admissibility_code>NL</time_recording_admissibility_code>
    <time_recording_profile_code>NL</time_recording_profile_code>
    <time_recording_variant>DURATION</time_recording_variant>
    <time_type_profile_code>NL20+/CI+</time_type_profile_code>
    <timezone>Europe/Amsterdam</timezone>
    <workingDaysPerWeek>5.0</workingDaysPerWeek>
    <workschedule_code>DUMMY</workschedule_code>
  </job_information>
</employment_information>

【问题讨论】:

    标签: xml sorting xslt


    【解决方案1】:

    您需要做的是复制其他节点(&lt;employment_information&gt; 的子节点,但不是 &lt;job_information&gt; 的子节点)

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" indent="yes"/>
    
      <xsl:template match="node() | @*">
        <xsl:copy>
          <xsl:apply-templates select="node() | @*" />
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="employment_information">
        <xsl:copy>
          <xsl:apply-templates select="node()[not(self::job_information)] | @*" />
          <xsl:apply-templates select="job_information">
            <!--  concat year, month, day -->
            <xsl:sort select="concat(
              substring(start_date, 1, 4),
              substring(start_date, 6, 2),
              substring(start_date, 9, 2) 
            )" data-type="number" order="ascending"/>
         </xsl:apply-templates>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    我使用了&lt;xsl:apply-templates select="node()[not(self::job_information)] | @*" /&gt;,因为这会触发身份模板,最终将复制这些节点。但在这种特殊情况下,&lt;xsl:copy-of select="node()[not(self::job_information)] | @*" /&gt; 也可以正常工作。


    Michael 的评论是正确的 - 这是没有明确说明所需子订单的不幸后果。为了保持原来的元素顺序,可以更细粒度地定位内部&lt;xsl:apply-templates&gt;,比如

    <!-- 1. all child nodes that come before the <job_information> block -->
    <xsl:apply-templates select="node()[not(self::job_information) and following-sibling::job_information]" />
    
    <!-- 2. the <job_information> block itself -->
    <xsl:apply-templates select="job_information">
      <xsl:sort ... />
    </xsl:apply-templates>
    
    <!-- 3. all child nodes that come after the <job_information> block -->
    <xsl:apply-templates select="node()[not(self::job_information) and preceding-sibling::job_information]" />
    

    但是这种方法需要保证&lt;job_information&gt; 元素是一个块,中间没有杂散元素。最后的决定是当其他节点切换位置时是否有任何中断,或者您的用例是否足以让&lt;job_information&gt; 以正确的顺序出现。

    【讨论】:

    • @Tom64 请注意,这将移动 job_event_information 并将其放在所有 job_information 节点之前。如果这是可以接受的,那么这对您应该很有效。 -- 另外,你可以简单地使用&lt;xsl:sort select="start_date"/&gt; 而不是所有的爵士乐。
    • 确实job_event_information由于模板的较早应用而移动了,但这不是问题。
    • 而且我不需要那些爵士乐 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-03
    • 2016-02-15
    • 1970-01-01
    • 2018-03-17
    • 1970-01-01
    • 2016-08-27
    相关资源
    最近更新 更多