Как сгруппировать разные элементы без идентификаторов, удалить дубликаты и добавить идентификатор группы в xslt? - PullRequest
0 голосов
/ 17 февраля 2019

Я хочу перегруппировать два элемента внутри нового элемента на основе их положения в списке, удалить дубликаты этих пар, отсортировать их в алфавитном порядке и дать каждой группе числовой идентификатор (используя XSLT 2.0 или 1.0).Я новичок в XSLT и в настоящее время в полной растерянности, как решить мою проблему.

В плоском XML-списке ориентиров (из базы данных) есть список имен для ориентиров и списоккоординат.Их необходимо переставить так, чтобы каждое имя и координата были правильно сгруппированы внутри нового элемента ориентира.Имя в позиции 1 должно быть в паре с первым элементом координат и т. Д.

В течение последних трех дней я просматривал темы для перегруппировки, удаления дубликатов, группирования muenchian в stackoverflow и пробовал опубликованные примерыно я не могу применить это к моему делу.

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

<?xml version="1.0" encoding="UTF-8"?>
<landmarklist>
  <citylist id="1">
    <landmark type="city">
      <name>London</name>
    </landmark>
    <landmark>
      <name>Tower Bridge</name>
      <name>Big Ben</name>
      <name>St Paul's Cathedral</name>
      <name>Big Ben</name>
      <coord>51°30′20″N 0°04′31″W</coord>
      <coord>51° 30′ 3″ N, 0° 7′ 28″ W</coord>
      <coord>51° 30′ 49″ N, 0° 5′ 53″ W</coord>
      <coord>51° 30′ 3″ N, 0° 7′ 28″ W</coord>
    </landmark>
  </citylist>
  <citylist id="2">
    <landmark type="city">
      <name>Paris</name>
    </landmark>
    <landmark>
      <name>Eiffel Tower</name>
      <name>Arc de Triomphe</name>
      <name>Louvre</name>
      <coord>48° 51′ 29.6″ N, 2° 17′ 40.2″ E</coord>
      <coord>48° 52′ 25.68″ N, 2° 17′ 42″ E</coord>
      <coord>48° 51′ 40″ N, 2° 20′ 11″ E</coord>
    </landmark>
  </citylist>
  <citylist id="3">
    <landmark type="city">
      <name>Madrid</name>
    </landmark>
    <landmark>
      <name>Plaza Mayor</name>
      <name>Almudena Cathedral</name>
      <coord>40° 24′ 55.31″ N, 3° 42′ 26.63″ W</coord>
      <coord>40° 24′ 56.11″ N, 3° 42′ 52.41″ W</coord>
    </landmark>
  </citylist>
</landmarklist>

Полученный выходной файл должен выглядеть так:

<?xml version="1.0" encoding="UTF-8"?>
<landmarklist>
<citylist id="1">
  <landmark type="city">
    <name>London</name>
  </landmark>
  <landmark id="1">
    <name>Big Ben</name>
    <coord>51° 30′ 3″ N, 0° 7′ 28″ W</coord>
  </landmark>
  <landmark id="2">
    <name>St Paul's Cathedral</name>
    <coord>51° 30′ 49″ N, 0° 5′ 53″ W</coord>
  </landmark>
  <landmark id="3">
    <name>Tower Bridge</name>
    <coord>51°30′20″N 0°04′31″W</coord>
  </landmark>
</citylist>
 <citylist id="2">
   <landmark type="city">
     <name>Paris</name>
   </landmark>
   <landmark>
     <name id="4">Arc de Triomphe</name>
     <coord>48° 52′ 25.68″ N, 2° 17′ 42″ E</coord>
   </landmark>
   <landmark>
     <name id="5">Eiffel Tower</name>
     <coord>48° 51′ 29.6″ N, 2° 17′ 40.2″ E</coord>
   </landmark>
   <landmark id="6">
     <name>Louvre</name>
     <coord>48° 51′ 40″ N, 2° 20′ 11″ E</coord>
   </landmark>
 </citylist>
  <citylist id="3">
    <landmark type="city">
      <name>Madrid</name>
    </landmark>
    <landmark id="7">
      <name>Plaza Mayor</name>
      <coord>40° 24′ 55.31″ N, 3° 42′ 26.63″ W</coord>     
    </landmark>
    <landmark id="8">
      <name>Almudena Cathedral</name>
      <coord>40° 24′ 56.11″ N, 3° 42′ 52.41″ W</coord>
    </landmark>
  </citylist>
</landmarklist>

Чтобы использовать ключ для группировкиЭлемент name и координата Я использовал отдельное преобразование для добавления идентификаторов (и я временно переименовал название города, чтобы оно не учитывалось для идентификаторов).Или можно управлять всем в собственном сценарии преобразования?

  <landmark>
     <name id="1">Tower Bridge</name>
     <name id="2">Big Ben</name>
     <name id="3">St Paul's Cathedral</name>
     <name id="4">Big Ben</name>
     <coord id="1">51°30′20″N 0°04′31″W</coord>
     <coord id="2">51° 30′ 3″ N, 0° 7′ 28″ W</coord>
     <coord id="3">51° 30′ 49″ N, 0° 5′ 53″ W</coord>
     <coord id="4">51° 30′ 3″ N, 0° 7′ 28″ W</coord>
  </landmark>

Но как теперь использовать идентификатор двух разных элементов для перегруппировки?Примеры, которые я нашел, всегда использовали один, насколько я понимаю?Мне очень жаль, что я не понимаю, как все это работает.

Любая помощь будет принята с благодарностью.Большое спасибо.

1 Ответ

0 голосов
/ 17 февраля 2019

Вы можете группировать и сортировать за один проход и во втором использовании xsl:number для атрибутов id. Ниже приведен XSLT 3 (работает с Saxon 9.8 или более поздней версии или Altova 2017 или более поздней версии):

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

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

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

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

  <xsl:variable name="first-pass">
      <xsl:apply-templates mode="group"/>
  </xsl:variable>

  <xsl:template match="/">
      <xsl:apply-templates select="$first-pass/node()"/>
  </xsl:template>

  <xsl:template match="citylist/landmark[not(@type)]" mode="group">
      <xsl:variable name="coords" select="coord"/>
      <xsl:for-each-group select="name" composite="yes" group-by="., let $p := position() return $coords[$p]">
          <xsl:sort select="current-grouping-key()[1]"/>
          <landmark>
              <xsl:copy-of select="."/>
              <coord>{current-grouping-key()[2]}</coord>
          </landmark>
      </xsl:for-each-group>
  </xsl:template>

  <xsl:template match="citylist/landmark[not(@type)]">
      <xsl:copy>
          <xsl:attribute name="id">
              <xsl:number level="any" count="landmark[not(@type)]"/>
          </xsl:attribute>
          <xsl:apply-templates/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / pPzifp8 / 1

Конечно, при необходимости может быть адаптирован к XSLT 2:

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

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

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

  <xsl:variable name="first-pass">
      <xsl:apply-templates mode="group"/>
  </xsl:variable>

  <xsl:template match="/">
      <xsl:apply-templates select="$first-pass/node()"/>
  </xsl:template>

  <xsl:template match="citylist/landmark[not(@type)]" mode="group">
      <xsl:variable name="coords" select="coord"/>
      <xsl:for-each-group select="name" group-by="concat(., '|', for $p in position() return $coords[$p])">
          <xsl:sort select="."/>
          <landmark>
              <xsl:variable name="p" select="position()"/>
              <xsl:copy-of select="., $coords[$p]"/>
          </landmark>
      </xsl:for-each-group>
  </xsl:template>

  <xsl:template match="citylist/landmark[not(@type)]">
      <xsl:copy>
          <xsl:attribute name="id">
              <xsl:number level="any" count="landmark[not(@type)]"/>
          </xsl:attribute>
          <xsl:apply-templates/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

http://xsltransform.net/gVAjbSZ

...