Я изучаю аккумуляторы в XSLT 3.0, но не нахожу примеров, которые помогли бы мне решить мою текущую проблему. У меня есть большие файлы, в которых инструкции по обработке используются для пометки модификаций. Мне нужно обработать их в видимые маркеры для процесса обзора. С аккумулятором мне удалось отследить отображаемый код последней модификации. Все идет нормально.
Поскольку исходные файлы огромны, я создал простой образец входного XML, который показывает суть моей задачи, и адаптировал свой XSL, чтобы показать, что я пытаюсь сделать с аккумулятором.
Простой входной файл:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<div>
<p>Paragraph 1</p>
<?MyPI Start Modification 1?>
<p>Paragraph 2</p>
<p>Paragraph 3</p>
<?MyPI End Modification 1?>
</div>
<div>
<list>
<item>
<p>Paragraph 4</p>
<?MyPI Start Modification 1?>
<p>Paragraph 5</p>
<?MyPI End Modification 1?>
</item>
<item>
<?MyPI Start Modification 1?>
<p>Paragraph 6</p>
<p>Paragraph 7</p>
<?MyPI End Modification 1?>
<?MyPI Start Modification 2?>
<p>Paragraph 8</p>
<?MyPI End Modification 2?>
</item>
</list>
<p>Paragraph 9</p>
</div>
</root>
Мой XSL с аккумулятором для текущей модификации:
<?xml version="1.0" encoding="UTF-8"?>
<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 use-accumulators="#all"/>
<xsl:accumulator name="modifier" initial-value="'Base text'">
<xsl:accumulator-rule match="processing-instruction('MyPI')[contains(.,'Modification')]">
<xsl:choose>
<xsl:when test="contains(.,'Start')">
<xsl:value-of select="substring-after(.,'Start ')"/>
</xsl:when>
<xsl:otherwise>Base text</xsl:otherwise>
</xsl:choose>
</xsl:accumulator-rule>
</xsl:accumulator>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="processing-instruction('MyPI')">
<marker>
<xsl:value-of select="accumulator-after('modifier')"/>
</marker>
</xsl:template>
</xsl:stylesheet>
Вывод с этим XSL:
<?xml version="1.0" encoding="UTF-8"?><root>
<div>
<p>Paragraph 1</p>
<marker>Modification 1</marker>
<p>Paragraph 2</p>
<p>Paragraph 3</p>
<marker>Base text</marker>
</div>
<div>
<list>
<item>
<p>Paragraph 4</p>
<marker>Modification 1</marker>
<p>Paragraph 5</p>
<marker>Base text</marker>
</item>
<item>
<marker>Modification 1</marker>
<p>Paragraph 6</p>
<p>Paragraph 7</p>
<marker>Base text</marker>
<marker>Modification 2</marker>
<p>Paragraph 8</p>
<marker>Base text</marker>
</item>
</list>
<p>Paragraph 9</p>
</div>
</root>
У меня проблема в том, что закрывающие и открывающие маркеры для одного и того же кода модификации должны быть скрыты, когда между ними нет текста. Они могут следовать сразу друг за другом (что довольно просто), но между ними также могут быть границы нетекстовых элементов. Я попытался создать аккумулятор, который отслеживает весь текст с момента последнего маркера модификации, но это вызывает вложенные вызовы того же аккумулятора, что дает ошибку времени выполнения. Я ищу метод, который продолжает добавлять текст в аккумулятор и сбрасывает его в пустую строку при обнаружении модификации PI. Это мой пробный аккумулятор, который вызвал слишком много вложенных вызовов:
<xsl:accumulator name="text" initial-value="''">
<xsl:accumulator-rule match="node()">
<xsl:choose>
<xsl:when test="self::processing-instruction('MyPI')"/>
<xsl:when test="self::text()">
<xsl:value-of select="concat(accumulator-after('text'),.)"/>
</xsl:when>
</xsl:choose>
</xsl:accumulator-rule>
</xsl:accumulator>
Думаю, я еще не понимаю, как работает аккумулятор, что затрудняет получение желаемого результата.
Требуемый вывод для приведенного выше простого XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<div>
<marker>Base text</marker>
<p>Paragraph 1</p>
<marker>Modification 1</marker>
<p>Paragraph 2</p>
<p>Paragraph 3</p>
<marker>Base text</marker>
</div>
<div>
<list>
<item>
<p>Paragraph 4</p>
<marker>Modification 1</marker>
<p>Paragraph 5</p>
</item>
<item>
<p>Paragraph 6</p>
<p>Paragraph 7</p>
<marker>Mpdification 2</marker>
<p>Paragraph 8</p>
</item>
</list>
<marker>Base text</marker>
<p>Paragraph 9</p>
</div>
</root>
Надеясь, что кто-то может указать мне в правильном направлении. Я предполагаю, что накопление текстовых узлов, поскольку конкретный узел в обработке XML будет проблемой, которую необходимо решить большему количеству людей. В моем текущем случае мне не нужно фактическое текстовое содержимое, мне просто нужно знать, есть ли какой-либо видимый текст с момента последней PI (т.е. мне нужно удалить или игнорировать любые пробелы в этой проверке).
Если есть другой метод, не использующий аккумуляторы, это тоже хорошо.
Заранее благодарю за любую помощь
<marker>Base text</marker>
, где конечный<marker>Base text</marker>
в нужном выводе? - person Martin Honnen   schedule 14.04.2021$value
, чтобы получить текущее значение - person Martin Honnen   schedule 14.04.2021<?MyPI Start Modification 1?>
, т.е. с одинаковым номером. Это актуально? Или вы просто имеете дело с двумя братьями и сестрами, например.<?MyPI Start Modification n?>
и<?MyPI End Modification n?>
? - person Martin Honnen   schedule 14.04.2021