使用 `<xsl:apply-templates>` 排序后缺少一些子节点

Posted

技术标签:

【中文标题】使用 `<xsl:apply-templates>` 排序后缺少一些子节点【英文标题】:Missing some child nodes after sorting with `<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>

【问题讨论】:

【参考方案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由于模板的较早应用而移动了,但这不是问题。 而且我不需要那些爵士乐 :)

以上是关于使用 `<xsl:apply-templates>` 排序后缺少一些子节点的主要内容,如果未能解决你的问题,请参考以下文章

何时使用 Mono<List<Object>> 以及何时使用 Flux<Object> 用于 RestController 方法

我应该使用 <colgroup> 和 <col>,如果是,为啥以及如何使用?

如何使用 Python 使用 Selenium 获取 <ul> 中的 <li> 元素列表?

<q>、<blockquote> 和 <cite> 的有效使用

使用运算符 << 将 std::strings 推送到向量中

标准库 array 的使用