Как превратить <revst/> ... element(s) ... <revend/> в элементы с установленным атрибутом (revst/revend могут быть на разных уровнях)

Я хочу включить ручной ввод SGML/XML этого самолета, который содержит теги revst/revend:

<em>
  <revst/>
  <prclist>
    <title>This list of steps was added</title> 
  </prclist>
  <prclist>
    <title>Another list of steps was added</title> 
  </prclist>
  <revend/>

  <chapter>
    <WARNING>
      <revst/>
      <PARA>First changed paragraph showing revst at deeper depth.</PARA>
    </WARNING>
    <PARA>Second changed paragraph showing revst at deeper depth.</PARA>
    <revend/>
  </chapter>

  <listitem>
    <revst/>
    <PARA>First changed paragraph showing revst at higher depth</PARA>
    <NOTE>
      <PARA>Second changed paragraph showing revst at higher depth</PARA>
      <revend/>
    </NOTE>
  </listitem>

  <prclist>
    <title>This list of steps was unchanged</title> 
  </prclist>
    
  <para>
    Some text
    <revst/>and some changed text here.<revend/>
    This text didn't change.
  </para>
</em>

В это:

<em>
  <prclist revised = "1">
    <title revised = "1">This list of steps was added</title> 
  </prclist>
  <prclist revised = "1">
    <title revised = "1">Another list of steps was added</title> 
  </prclist>

  <chapter>
    <WARNING>
      <PARA revised = "1">First changed paragraph showing revst at deeper depth.</PARA>
    </WARNING>
    <PARA revised = "1">Second changed paragraph showing revst at deeper depth.</PARA>
  </chapter>

  <listitem>
    <PARA revised = "1">First changed paragraph showing revst at higher depth</PARA>
    <NOTE revised = "1">
      <PARA revised = "1">Second changed paragraph showing revst at higher depth</PARA>
    </NOTE>
  </listitem>

  <prclist>
    <title>This list of steps was unchanged</title> 
  </prclist>

  <para>
    Some text
    <span revised = "1">and some changed text here.</span>
    This text didn't change.
  </para>
</em>

Причина: я считаю, что установка атрибута «пересмотрено» для всех тегов (в первом проходе обработки) облегчит окончательное преобразование HTML во втором проходе. Если сделать этот проход в xsl 3 непросто/чисто, я просто напишу программу для этого.

Конечная цель состоит в том, чтобы установить цвет фона в HTML для всех «пересмотренных» элементов/текста.

Предположим, что пары revst/reven не могут перекрывать друг друга во входном документе.

Вы можете использовать XSLT 2 или 3?

Martin Honnen 05.02.2023 17:27

В настоящее время используется xsl 3/saxon 11

KP99 05.02.2023 17:31
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Чтобы идентифицировать узлы «внутри» <revst/>..<revend/>, вы можете использовать вложенный for-each-group group-starting-with/group-ending-with; с XSLT 3 вы можете хранить группы в переменной как последовательность массивов и передавать эту переменную как параметр туннеля через режим, который проверяет, являются ли узлы частью группы, и добавляет атрибут:

<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
  version = "3.0"
  xmlns:xs = "http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes = "#all">
  
  <xsl:template match = "/*">
    <xsl:variable name = "rev-groups" as = "array(node())*">
      <xsl:for-each-group select = "descendant::node()" group-starting-with = "revst">
        <xsl:if test = "self::revst">
          <xsl:for-each-group select = "tail(current-group())" group-ending-with = "revend">
            <xsl:if test = "current-group()[last()][self::revend]">
              <xsl:sequence select = "array{ current-group()[position() lt last()] }"/>
            </xsl:if>
          </xsl:for-each-group>
        </xsl:if>
      </xsl:for-each-group>      
    </xsl:variable>
    <xsl:copy>
      <xsl:apply-templates select = "@*, node()">
        <xsl:with-param name = "rev-groups" tunnel = "yes" select = "$rev-groups"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:mode on-no-match = "shallow-copy"/>
  
  <xsl:template match = "text()[normalize-space()]">
    <xsl:param name = "rev-groups" tunnel = "yes"/>
    <xsl:choose>
      <xsl:when test = ". intersect $rev-groups?1">
        <span revised = "1">
          <xsl:next-match/>
        </span>
      </xsl:when>
      <xsl:otherwise>
        <xsl:next-match/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xsl:template match = "*">
    <xsl:param name = "rev-groups" tunnel = "yes"/>
    <xsl:choose>
      <xsl:when test = ". intersect $rev-groups?*">
        <xsl:copy>
          <xsl:attribute name = "revised" select = "1"/>
          <xsl:apply-templates select = "@*, node()"/>
        </xsl:copy>
      </xsl:when>
      <xsl:otherwise>
        <xsl:next-match/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xsl:template match = "revst | revend"/>

</xsl:stylesheet>

Я думаю, что для элементов с добавленным атрибутом revised код работает хорошо, код для переноса других узлов в span revised, вероятно, не будет работать, как опубликовано, если также появятся комментарии или инструкции по обработке. Я также не уверен, что эта часть требования четко указана в одном примере.

Я разместил решение с использованием аккумулятора, которое кажется более простым и решает обе части требований.

KP99 05.02.2023 18:37

@ KP99, хорошая идея сохранить состояние в аккумуляторе, но я думаю, что его также нужно настроить, поскольку в настоящее время кажется, что он производит больше span revised = "1" (например, вокруг элементов), чем ваш желаемый результат. Также до сих пор не ясно, какой результат вы хотите с комментариями или инструкциями по обработке.

Martin Honnen 05.02.2023 18:52
Ответ принят как подходящий

Вау, с аккумулятором получилось намного чище, чем я думал.

Эта таблица стилей:

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

<xsl:mode use-accumulators = "revisionCheck"/>

<xsl:template match = "/">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match = "*">
  <xsl:variable name = "revised" select = "accumulator-before('revisionCheck')"/>
  <xsl:copy>
    <xsl:if test = "$revised = 1">
      <!-- Add a "revised" attribute to this element -->
      <xsl:attribute name = "revised" select = "$revised"></xsl:attribute>
    </xsl:if>
    <xsl:apply-templates>
      <!-- Pass a parameter indicating if we are already inside a revised parent element.
           This is useful for eliminating redundant <spans> in text nodes. -->
      <xsl:with-param name = "parent_revised" select = "$revised"/>
    </xsl:apply-templates>
  </xsl:copy>
</xsl:template>

<!-- Remove these tags from the output. -->
<xsl:template match = "revst | revend">
</xsl:template>

<!-- 
  Copy text.  If it is revised and NOT already in a revised parent element, wrap it in a span.
  -->
<xsl:template match = "text()">
  <xsl:param name = "parent_revised" />
  <xsl:variable name = "revised" select = "accumulator-before('revisionCheck')"/>
  <xsl:choose>
    <xsl:when test = "$revised = 1 and $parent_revised != 1">
      <span revised = "{$revised}"><xsl:value-of select = "."/></span>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select = "."/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- 
Keep track of when we see revst and revend tags.
This seems to work even when revst is at a deeper level than the ending revend,
or vice-versa, yay! 
Note that it doesn't matter what phase we use (start or end), because the tags
don't contain any children.
-->
<xsl:accumulator name = "revisionCheck" as = "xs:integer" initial-value = "-1" >
  <xsl:accumulator-rule match = "revst" select = "1"/>
  <xsl:accumulator-rule match = "revend" select = "0"/>
</xsl:accumulator>

</xsl:stylesheet>

Производит этот вывод, как раз то, что я хотел:

<?xml version = "1.0" encoding = "UTF-8"?>
<em>
  <prclist revised = "1">
    <title revised = "1">This list of steps was added</title>
  </prclist>
  <prclist revised = "1">
    <title revised = "1">Another list of steps was added</title>
  </prclist>
  <chapter>
    <WARNING>
      <PARA revised = "1">First changed paragraph showing revst at deeper depth.</PARA>
    </WARNING>
    <PARA revised = "1">Second changed paragraph showing revst at deeper depth.</PARA>
  </chapter>
  <listitem>
    <PARA revised = "1">First changed paragraph showing revst at lower depth</PARA>
    <NOTE revised = "1">
      <PARA revised = "1">Second changed paragraph showing revst at lower depth</PARA>
    </NOTE>
  </listitem>
  <prclist>
    <title>This list of steps was unchanged</title>
  </prclist>
  <para>
    Some text
    <span revised = "1">and some changed text here.</span>
    This text didn't change.
  </para>
</em>

Другие вопросы по теме