Как сравнить братьев и сестер из одной группы?

#xslt #xslt-2.0 #xslt-grouping #xslt-3.0

#xslt #xslt-2.0 #xslt-группировка #xslt-3.0

Вопрос:

У меня есть фрагмент кода, который выглядит следующим образом:

 <root>
   <applicant>
     <id>XYZ</id>
     <group>
        <start_date>2019-04-01</start_date>
        <end_date>2019-04-01</end_date>
     </group>
     <group>
        <start_date>2019-04-02</start_date>
        <end_date>2019-04-02</end_date>
     </group>
     <group>
        <start_date>2019-04-03</start_date>
        <end_date>2019-04-03</end_date>
     </group>
  </applicant>
  <applicant>
     <id>ABC</id>
     <group>
        <start_date>2019-05-01</start_date>
        <end_date>2019-05-01</end_date>
     </group>
     <group>
        <start_date>2019-05-02</start_date>
        <end_date>2019-05-02</end_date>
     </group>
     <group>
        <start_date>2019-05-03</start_date>
        <end_date>2019-05-03</end_date>
     </group>
  </applicant>
</root>
 

и мне нужно сгруппировать его по кандидатам и объединить в один узел с единой датой начала и датой окончания, если дата от следующего родного брата отличается на 1 день (разница в днях равна 1)

итак, для приведенного выше кода для достижения чего-то вроде:

 <root>
  <applicant>
    <id>XYZ</id>
    <start_date>2019-04-01</start_date>
    <end_date>2019-04-03</end_date>
  </applicant>
  <applicant>
    <id>ABC</id>
    <start_date>2019-05-01</start_date>
    <end_date>2019-05-03</end_date>
  </applicant>
</root>
 

Я думал об использовании следующего-sibling:: или какого-то повторения.

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

1. Если вы действительно можете использовать XSLT 2.0 или 3.0, то я бы удалил тег XSLT-1.0 из вопроса, чтобы уточнить, какую версию вы можете использовать (особенно потому, что любое решение XSLT 1.0 было бы совсем непростым). Спасибо!

Ответ №1:

Предполагая, что вы действительно можете использовать XSLT 2.0 или выше, вы могли бы использовать xsl:for-each-group here и group, начиная с элементов, которые start_date - 1 не соответствуют end_date предыдущей группе.

Попробуйте этот XSLT

 <xsl:stylesheet 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     exclude-result-prefixes="xs"
     version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes" />

  <xsl:template match="applicant">
    <xsl:copy>
      <xsl:copy-of select="id" />
      <xsl:for-each-group select="group" group-starting-with="group[not(xs:date(start_date) - xs:dayTimeDuration('P1D') = xs:date(preceding-sibling::group[1]/end_date))]">
        <group>
          <xsl:copy-of select="start_date, current-group()[last()]/end_date" />
        </group>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
 

(Для этого используется XSLT 3.0. В XSLT 2.0 все, что вам нужно сделать xsl:mode , это заменить шаблон идентификатора на)

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

1. Очень хороший ответ. Я думаю, что следует что-то сказать об использовании такого специального условия, чтобы не иметь первой несоответствующей группы.