Как сделать, чтобы внутренний элемент текстового узла включал текст после элемента - PullRequest
0 голосов
/ 06 мая 2019

Авторы XML-документа не включали весь текст внутри элемента, который будет преобразован в гиперссылку.Я хотел бы обработать или предварительно обработать XML, чтобы включить необходимый текст.Мне трудно это описать, но простой пример должен показать, что я пытаюсь сделать.Я использую XSLT 2.0.Я уже выполняю обработку регулярных выражений для различных ситуаций, но не могу понять это.

Я знаю, как сделать это с помощью регулярного выражения perl / python, но я не могу понять, как подойти к этому с помощью XSLT.

Вот «очень» упрощенный xml от автора, в котором они исключили «(Лист 3)» из элемента glink .:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <para>
        Go look at figure <glink refid=1>Figure 22</glink> (Sheet 3). Then go do something else.
    </para>
</root>

Вот что мне нравитсяпреобразовать туда, где '(лист 3)' теперь находится внутри тега glink:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <para>
        Go look at figure <glink refid=1>Figure 22 (Sheet 3)</glink>. Then go do something else.
    </para>
</root>

Случай, когда должно произойти это преобразование, - это когда за элементом glink следует (это регулярное выражение):

\s\(Sheet \d\)

В настоящее время у меня есть 2 XSLT.Первый предварительно обрабатывает XML для преобразования ряда других ситуаций (используя регулярное выражение / xsl: analysis-string).Второй XSLT для преобразования из предварительно обработанного XML в HTML.Второй XSLT имеет шаблон для обработки элементов блеска и превращения его в гиперссылку, но гиперссылка должна включать информацию листа.

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

Ответы [ 3 ]

1 голос
/ 06 мая 2019

Существующий ответ имеет правильный подход, но я бы уточнил шаблон регулярного выражения и шаблоны соответствия:

  <xsl:param name="pattern" as="xs:string">\s\(Sheet \d\)</xsl:param>

  <xsl:variable name="pattern2" as="xs:string" select="'^' || $pattern"/>
  <xsl:variable name="pattern3" as="xs:string" select="'^(' || $pattern || ')(.*)'"/>

  <xsl:template match="glink[@refid][following-sibling::node()[1][self::text()[matches(., $pattern2)]]]">
      <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:value-of select=". || replace(following-sibling::node()[1], $pattern3, '$1', 's')"/>
      </xsl:copy>
  </xsl:template>

  <xsl:template match="text()[preceding-sibling::node()[1][self::glink[@refid]]][matches(., $pattern2)]">
      <xsl:value-of select="replace(., $pattern3, '$2', 's')"/>
  </xsl:template>

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

В противном случае, я думаю, что совпадения и замены происходят более чем на glink с последующим (непосредственно?) Этим шаблоном, как вы можете видеть в https://xsltfiddle.liberty -development.net / bFN1y9z / 2 .

В коде, который я разместил, используется оператор конкатенации строк || XPath 3.1, но если целью является процессор XSLT 2, который, конечно, можно заменить обычным вызовом функции concat.

1 голос
/ 06 мая 2019

Чтобы сократить использование функций регулярных выражений, я бы использовал этот подход:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="glink">
    <xsl:variable name="vAnalyzedString">
        <xsl:analyze-string 
            select="following-sibling::node()[1][self::text()]"
            regex="^\s*\(Sheet\s+\d+\)">
            <xsl:matching-substring>
                <match>
                    <xsl:value-of select="."/>
                </match>
            </xsl:matching-substring>
            <xsl:non-matching-substring>
                <no-match>
                    <xsl:value-of select="."/>
                </no-match>
            </xsl:non-matching-substring>
        </xsl:analyze-string>
    </xsl:variable>
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
      <xsl:apply-templates 
        select="$vAnalyzedString/match/text()"/>
    </xsl:copy>
    <xsl:apply-templates 
        select="$vAnalyzedString/no-match/text()"/>
  </xsl:template>

  <xsl:template match="text()[preceding-sibling::node()[1][self::glink]]"/>
</xsl:stylesheet>

Выход:

<root>
   <para>
        Go look at figure <glink refid="1">Figure 22 (Sheet 3)</glink>. Then go do something else.
    </para>
</root>

Обратите внимание : все glink обрабатываются, но ни один из этих текстовых узлов не является первыми братьями и сестрами. Можно использовать инструкцию xsl:analize-string, но вам нужно будет объявить переменную с частичными результатами, а затем пересмотреть эти результаты. Кроме того, этот подход может легко позволить вам продолжить обработку этих (сейчас) текстовых узлов, и он имеет только одну обработку регулярных выражений .

0 голосов
/ 06 мая 2019

Вы можете использовать эти два шаблона в сочетании с шаблоном идентификации :

<xsl:template match="glink">
    <xsl:copy>
        <xsl:copy-of select="@*|text()" />
        <xsl:text> </xsl:text>
        <xsl:value-of select="normalize-space(replace(following::text()[1],'\s(\(Sheet \d\)).*',' $1'))" />
    </xsl:copy>
</xsl:template> 

<xsl:template match="text()[preceding-sibling::glink]">
    <xsl:value-of select="normalize-space(replace(.,'\s\(Sheet \d\)(.*)',' $1'))" />
</xsl:template> 

Первый включает строку (Sheet 3) в glink, а второй исключает (Sheet 3) из следующего text() узла.

Результат:

<root>
    <para>
        Go look at figure <glink refid="1">Figure 22 (Sheet 3)</glink>. Then go do something else.</para>
</root>
...