Как сгладить группы смежных одинаковых узлов? - PullRequest
1 голос
/ 23 июня 2019

Предположим, у меня есть следующая последовательность элементов:

<outer>
  <e>…</e>  <!-- Adjacent <e> should be grouped if they aren’t yet. -->
  <e>…</e>
  <group>
    <e>…</e>
    <e>…</e>
  </group>
  <e>…</e>
  <e>…</e>
</outer>

И я хотел бы объединить те элементы <e>, которые еще не были сгруппированы, т.е. результат будет

<outer>
  <group-foo>  <!-- Grouped elements. -->
    <e>…</e>
    <e>…</e>
  </group-foo>
  <group-bar>
    <e>…</e>
    <e>…</e>
  </group-bar>
  <group-foo>
    <e>…</e>
    <e>…</e>
  </group-foo>
</outer>

Я просто не могу понять, как выбрать группу смежных элементов (набор узлов); Ближайшая идея заключалась в том, чтобы выбрать //e[name(parent::*) = 'outer'] или что-то подобное, но при этом предполагается наличие определенного родительского элемента, и он возвращает один набор узлов, тогда как мне нужно два.

Ответы [ 2 ]

1 голос
/ 23 июня 2019

Один из способов решить эту проблему - использовать так называемую рекурсию брата :

XSLT 1.0

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

<xsl:template match="/outer">
    <xsl:copy>
        <xsl:apply-templates select="e[not(preceding-sibling::*[1][self::e])] | group"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="e">
    <group-foo>
        <xsl:copy-of select="."/>
        <!-- immediate sibling in the same group -->
        <xsl:apply-templates select="following-sibling::*[1][self::e]" mode="collect" />
    </group-foo>
</xsl:template>

<xsl:template match="e" mode="collect">
    <xsl:copy-of select="."/>
    <!-- immediate sibling in the same group -->
    <xsl:apply-templates select="following-sibling::*[1][self::e]" mode="collect" />
</xsl:template> 

<xsl:template match="group">
    <group-bar>
        <xsl:copy-of select="*"/>
    </group-bar>
</xsl:template> 

</xsl:stylesheet>
0 голосов
/ 23 июня 2019

Нет рекурсии.Использование ключей ( мюнхенская группировка ):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kE-ByPrecedingNonE" match="e[not(name(..) = 'group')]"
   use="generate-id(preceding-sibling::*[not(self::e)][1])"/>

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

  <xsl:template match="e[not(name(..) = 'group')]"/>

  <xsl:template match=
   "e[generate-id()
    = generate-id(key('kE-ByPrecedingNonE',
                      generate-id(preceding-sibling::*[not(self::e)][1])
                      )[1]
                  )]">
      <group-generated>
        <xsl:apply-templates select=
        "key('kE-ByPrecedingNonE',
             generate-id(preceding-sibling::*[not(self::e)][1])
             )" mode="inGroup"/>
      </group-generated>
    </xsl:template>

    <xsl:template match="node()" mode="inGroup">
      <xsl:call-template name="identity"/>
    </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к предоставленному документу source-xml :

<outer>
  <e>…</e>
  <e>…</e>
  <group>
    <e>…</e>
    <e>…</e>
  </group>
  <e>…</e>
  <e>…</e>
</outer>

желаемый правильный результат получен :

<outer>
   <group-generated>
      <e>…</e>
      <e>…</e>
   </group-generated>
   <group>
      <e>…</e>
      <e>…</e>
   </group>
   <group-generated>
      <e>…</e>
      <e>…</e>
   </group-generated>
</outer>

Пояснение :

  1. Правило идентификации (шаблон) копирует на выход каждый узел как есть.Мы также даем ему имя, чтобы мы могли не только использовать его при применении шаблонов, но и вызывать его напрямую - как мы это делаем в шаге 4. ниже.

  2. Шаблон, соответствующий любому<e> элемент, которого еще нет внутри <group>.Это не имеет тела - мы хотим обрабатывать только такие элементы в наших следующих шаблонах - не тогда, когда шаблон идентификации выбирает его для выполнения.

  3. Шаблон, который соответствует любому элементу <e>это первое в «непокрытой» группе.Здесь используется идея метода группирования по Мюнхену - если вы не знакомы с ним, изучите его хорошо - вы не пожалеете.Этот шаблон генерирует элемент оболочки (называемый «сгенерированный группой») для всей группы, и внутри этой оболочки применяется шаблоны ко всем <e> в группе в режиме «inGroup» - где они просто копируются.

  4. Шаблон в режиме "inGroup" просто делегирует правило идентификации для копирования выбранного узла.Таким образом, любой соответствующий узел копируется как есть.Здесь, если мы решим, мы можем выполнить любую другую необходимую обработку inGroup.

...