Перебирать узлы, содержащие CDATA, и объединять их, а также как извлекать конкретные данные из сцепленных данных.

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

<a>
  <b1><![CDATA[<CdtrRefInf><Issr>XXX</Issr></Tp><Ref>123456123]]></b1>
  <b2><![CDATA[193</Ref></CdtrRefInf>]]></b2>
</a>

Ожидаемый результат должен быть:

<a>
  <b1>123456123193<b1>
</a>

Мне нужно перебрать элементы b1 и b2 и объединить содержимое в переменную. Затем мне нужно взять содержимое элемента Ref и поместить его в элемент b1. Следующий код объединяет содержимое полей b1 и b2 вместе. Но как это поставить в вышеуказанном формате?????

<xsl:template match="/*">
    <xsl:variable name="vMyVars">
        <xsl:apply-templates select="b1 | b2 " mode="vMyVars"/>
    </xsl:variable>
    <xsl:value-of select="substring($vMyVars, -1, string-length($vMyVars))"/>
</xsl:template>

<xsl:template match="*" mode="vMyVars"/>

<xsl:template match="*[normalize-space()]" mode="vMyVars">
    <xsl:value-of select="."/>
    <!--<xsl:text>, </xsl:text>-->
</xsl:template>

Любой совет приветствуется. С уважением Дирк

1 ответ

Решение

Для этого вам понадобится XPath 3.0 (XSLT 3.0). Просто используйте:

 parse-xml(concat(/*/b1, /*/b2))/*/Ref/text()

Вам также необходимо исправить текст внутри разделов CDATA - он содержит </Tp> - закрывающий тег, который не имеет соответствующего начального тега. Я исправил это, чтобы: <Tp/>,

С этим исправлением к предоставленному документу XML теперь:

<a>
  <b1><![CDATA[<CdtrRefInf><Issr>XXX</Issr></Tp><Ref>123456123]]></b1>
  <b2><![CDATA[193</Ref></CdtrRefInf>]]></b2>
</a>

Оценка приведенного выше выражения XPath 3.0 в приведенном выше документе XML дает желаемый, правильный результат:

123456123193

Я проверил это с помощью BaseX, используя этот XQuery 3.0:

let $top :=
<a>
  <b1><![CDATA[<CdtrRefInf><Issr>XXX</Issr><Tp/><Ref>123456123]]></b1>
  <b2><![CDATA[193</Ref></CdtrRefInf>]]></b2>
</a>

 return
    parse-xml(concat($top/b1, $top/b2))/*/Ref/text()

II. Решение в XSLT 2.0

XSLT 2.0 не предоставляет простой функции или инструкции для разбора строки в документ / фрагмент XML.

В Saxon можно использовать функцию расширения saxon:parse():

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:saxon="http://saxon.sf.net/">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/*">
     <xsl:copy-of select="saxon:parse(concat(/*/b1, /*/b2))/*/Ref/text()"/>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование выполняется с помощью Saxon 9.1.07 в предоставленном XML-документе:

<a>
  <b1><![CDATA[<CdtrRefInf><Issr>XXX</Issr><Tp/><Ref>123456123]]></b1>
  <b2><![CDATA[193</Ref></CdtrRefInf>]]></b2>
</a>

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

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