XSLT 2.0: фильтрация по узлам / тексту с помощью анализа строки, но также необходимо захватывать теги XML
Я работаю над своим первым крупным проектом XSLT, и я немного новичок, поэтому, пожалуйста, будьте терпеливы с моим невежеством.
Наша группа работает над преобразованием существующих XML-файлов в совершенно другую систему тегов. Я разработал систему обработки выносок MathType (обозначается как "${TEXT}") с использованием Analyze-String, но у меня возникают трудности с определением того, что я должен делать с кодом, таким как теги ital (обозначенные тегами "I")), которые необходимо сохранить в коде результата.
Я попытался использовать copy-of в не совпадающей подстроке, но это, похоже, не работает. Конечно, value-of дает мне все, кроме тегов ital.
Я понимаю, что переменная ($stemString) на данный момент лишняя. Я шел по этому пути, думая, что смогу придумать что-то, что позволит копировать процесс, но пока безуспешно.
Образец кода:
<stem>What is the value of <I>f</I>(<I>x</I>) when ${##A112800eqn01:3}</stem>
Мой текущий XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="assessmentItem">
<!--SNIP-->
<xsl:apply-templates select="stemArea/stem"/>
<!--SNIP-->
</xsl:template>
<xsl:template match="stem">
<xsl:variable name="stemString">
<xsl:copy-of select="./* | ./text()"/>
</xsl:variable>
<xsl:choose>
<!--Tests for empty stems that aren't art callouts-->
<xsl:when test=". = '' and @type!='art'"></xsl:when>
<xsl:when test=". = ' ' and @type!='art'"></xsl:when>
<!--Test for art callouts-->
<xsl:when test="@type='art'"><p><img alt="{@loc}" height="10" id="{@loc}" label="" longdesc="normal" src="{@loc}" width="10"/></p></xsl:when>
<!--Test for boxed text-->
<xsl:when test="@style='box' or @style='boxL'"><p><span label="Tag_7">
<xsl:copy-of select="./* | ./text()"></xsl:copy-of>
</span></p></xsl:when>
<xsl:otherwise><p>
<!--Are MathType tokens present in stem?-->
<xsl:analyze-string regex="(\$\{{.+\}})" select="$stemString">
<!--If MathType tokens are in stem, do the following-->
<xsl:matching-substring>
<xsl:analyze-string regex="(\$\{{)(##.+[eqn|art]\d+)([^a-zA-Z0-9]?.*\}})" select=".">
<xsl:matching-substring>
<img alt="{regex-group(2)}" height="10" id="{regex-group(2)}" label="" longdesc="normal" src="{regex-group(2)}" width="10"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:text>ERROR</xsl:text>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:matching-substring>
<!--No MathType tokens in string-->
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</p></xsl:otherwise>
</xsl:choose>
</xsl:template>
Желаемый результат:
<p>What is the value of <I>f</I>(<I>x</I>) when <img alt="##A112800eqn01" height="10" id="##A112800eqn01" label="" longdesc="normal" src="##A112800eqn01" width="10"/></p>
Что я получаю:
<p>What is the value of f(x) when <img alt="##A112800eqn01" height="10" id="##A112800eqn01" label="" longdesc="normal" src="##A112800eqn01" width="10"/></p>
У кого-нибудь есть идеи, как поступить?
@Martin Honnen: Спасибо за ответ. Ваш код решает ошибку.
Однако у меня есть дополнительная проблема. Когда в стволе более одного вызова MathType, это вызывает ошибку. Я уверен, что причина в том, что мое регулярное выражение не захватывает все должным образом, но какое-то время я прибивал к этому безрезультатно. Ниже я проиллюстрирую проблему, с которой я столкнулся.
Образец кода:
<stem type="text">What is the value of <I>f</I>(<I>x</I>) when ${##A112800eqn01:3}, and ${##A112800eqn02:3} is 3.</stem>
Желаемый результат:
<p>What is the value of <I>f</I>(<I>x</I>) when <img alt="##A112800eqn01" height="10" id="##A112800eqn01" label="" longdesc="normal" src="##A112800eqn01" width="10"/>, and <img alt="##A112800eqn02" height="10" id="##A112800eqn02" label="" longdesc="normal" src="##A112800eqn02" width="10"/> is 3.</p>
Что я получаю:
<p>What is the value of <I>f</I>(<I>x</I>) when <img alt="##A112800eqn01:3}, and ${##A112800eqn02" height="10" id="##A112800eqn01:3}, and ${##A112800eqn02" label="" longdesc="normal" src="##A112800eqn01:3}, and ${##A112800eqn02" width="10"/> is 3.</p>
1 ответ
Не сопоставлять элемент, а затем положить xsl:choose
внутри шаблона, чтобы отличать дальше, вместо этого просто напишите шаблоны для различных элементов или элементов с определенными значениями атрибутов.
И если вы хотите использовать analyze-string
затем сделать это в шаблоне text
узел, отсутствующий в шаблоне элемента, содержащего смешанное содержимое:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="assessmentItem">
<!--SNIP-->
<xsl:apply-templates select="stemArea/stem"/>
<!--SNIP-->
</xsl:template>
<xsl:template match="stem[. = '' and @type!='art'] | stem[. = ' ' and @type != 'art']"/>
<xsl:template match="stem[@style='box' or @style='boxL']">
<p><span label="Tag_7"><xsl:apply-templates/></span></p>
</xsl:template>
<xsl:template match="stem[.//text()[matches(., '\$\{.+\}')]]">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="stem//text()[matches(., '\$\{.+\}')]">
<xsl:analyze-string regex="(\$\{{)(##.+[eqn|art]\d+)([^a-zA-Z0-9]?.*\}})" select=".">
<xsl:matching-substring>
<img alt="{regex-group(2)}" height="10" id="{regex-group(2)}" label="" longdesc="normal" src="{regex-group(2)}" width="10"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
С этой таблицей стилей, применительно к вводу
<stem>What is the value of <I>f</I>(<I>x</I>) when ${##A112800eqn01:3}</stem>
Я получаю результат
<p>What is the value of <I>f</I>(<I>x</I>) when <img alt="##A112800eqn01" height="10" id="##A112800eqn01" label="" longdesc="normal" src="##A112800eqn01" width="10"/></p>
Вышеприведенное предназначено как предложение о том, как подходить к дизайну вашей таблицы стилей, скорее всего, оно не является полным решением, так как у меня не так много входных образцов для тестирования и я не знаю входной XML и текстовый формат, который вы пытаетесь обработать.
Я бы наверное реализовал
<xsl:template match="stem[. = '' and @type!='art'] | stem[. = ' ' and @type != 'art']"/>
как
<xsl:template match="stem[not(normalize-space()) and @type!='art']"/>
вместо этого, но я в основном пытался показать, как структурировать таблицу стилей с помощью шаблонов и как сопоставить на нисходящем текстовом узле stem
чтобы обеспечить analyze-string
не глотает узлы элементов внутри stem
,
Что касается вашего отредактированного входного требования, я изменил регулярное выражение для использования не жадного соответствия (.*?
), поэтому с помощью приведенного ниже кода вы сможете сопоставить несколько шаблонов в stem
создать несколько img
элементы:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="assessmentItem">
<!--SNIP-->
<xsl:apply-templates select="stemArea/stem"/>
<!--SNIP-->
</xsl:template>
<xsl:template match="stem[. = '' and @type!='art'] | stem[. = ' ' and @type != 'art']"/>
<xsl:template match="stem[@style='box' or @style='boxL']">
<p><span label="Tag_7"><xsl:apply-templates/></span></p>
</xsl:template>
<xsl:template match="stem[.//text()[matches(., '\$\{.+?\}')]]">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="stem//text()[matches(., '\$\{.+?\}')]">
<xsl:analyze-string regex="(\$\{{)(##.+?[eqn|art]\d+)([^a-zA-Z0-9]?.*?\}})" select=".">
<xsl:matching-substring>
<img alt="{regex-group(2)}" height="10" id="{regex-group(2)}" label="" longdesc="normal" src="{regex-group(2)}" width="10"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>