Отсутствуют некоторые дочерние узлы после сортировки с помощью «

#xml #sorting #xslt

#xml #сортировка #xslt

Вопрос:

Я пытаюсь отсортировать дочерние узлы на основе поля start_date. В приведенном ниже XML-узле <employment_information> есть два дочерних узла <job_information> с убывающей начальной датой, которая должна быть возрастающей.

После долгих поисков и попыток я добился того, что сортировка работает, но проблема, с которой я столкнулся, заключается в том, что другие поля <employment_information> исчезают. Узлы <job_information> расположены в правильном порядке, но другие поля исчезли.

Мой 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 ушли. Как я могу их сохранить? Чего мне не хватает?

 <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:

Что вам нужно сделать, это скопировать другие узлы (дочерние <employment_information> узлы, но не те, которые есть <job_information> ).

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

Я использовал <xsl:apply-templates select="node()[not(self::job_information)] | @*" /> , потому что это запускает шаблон идентификации, который в конечном итоге скопирует эти узлы. Но в данном конкретном случае <xsl:copy-of select="node()[not(self::job_information)] | @*" /> это сработает так же хорошо.


Комментарий Майкла верен — это печальное последствие того, что явно не указан желаемый дочерний порядок. Чтобы сохранить исходный порядок элементов, вы могли бы настроить таргетинг на внутренний <xsl:apply-templates> с более высокой степенью детализации, например

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

Но этот подход требует, чтобы <job_information> элементы гарантированно были блоком без посторонних элементов между ними. В конце концов, решение заключается в том, ломается ли что-либо, когда другие узлы меняют позиции, или этого достаточно для того, чтобы ваш вариант использования <job_information> отображался в правильном порядке.

Комментарии:

1. @Tom64 Обратите внимание, что это переместит job_event_information и разместит его перед всеми job_information узлами. Если это приемлемо, то это должно хорошо работать для вас. — Кроме того, вы могли бы сделать просто <xsl:sort select="start_date"/> вместо всего этого джаза.

2. Действительно, job_event_information переместился из-за более раннего применения шаблона, но это не проблема.

3. И мне не нужен был весь этот джаз 🙂