#xslt #xpath #xslt-2.0
#xslt #xpath #xslt-2.0
Вопрос:
Я уже несколько часов бьюсь над этим кодом XSL (Saxon / Java) и все еще не могу в нем разобраться. Я сузил проблему до этого фрагмента:
<xsl:function name="my:fff" >
<xsl:element name="p0">
<p1 aaa='AAA' />
</xsl:element>
</xsl:function>
<xsl:function name="my:ggg">
<xsl:variable name="v" select="my:fff()" />
<!-- Debug messages -->
<xsl:message>
$v '<xsl:sequence select="$v" />'
$v/* '<xsl:sequence select="$v/*" />'
$v/*/@aaa '<xsl:value-of select="$v/*/@aaa" />'
$v/p0 '<xsl:sequence select="$v/p0" />'
</xsl:message>
...
</xsl:function>
Вывод, выводимый in my:ggg
, выглядит следующим образом:
$v '<p0><p1 aaa="AAA"/></p0>'
$v/* '<p1 aaa="AAA"/>'
$v/*/@aaa 'AAA'
$v/p0 ''
Первые три строки в порядке. Но четвертая строка, которая выводит пустую строку, странная. Я имею в виду, если $v
есть <p0><p1 aaa="AAA"/></po>
(как указано в первой строке), то почему этого $v/p0
нет <p1 aaa="AAA"/>
?
Чего я не понимаю?
Комментарии:
1.
$v
элемент, возвращаемый с помощьюmy:fff
, поэтому он является тегом<p0>
, включающим дочерние элементы.$v/p0
пытается выбрать a<p0>
в качестве дочернего тега в$v
, который пуст, поскольку тег,<p0>
выбранный$v
, не содержит a<p0>
.2. @rsp — Вы должны сделать это ответом, так как это и есть на самом деле ответ.
Ответ №1:
Ваши рассуждения были бы в порядке, если бы my:fff()
функция возвращала узел документа, а не элемент ( p0
который сам по себе не имеет p0
дочернего элемента).
Итак, если вы измените функцию на следующую:
<xsl:function name="my:fff" as="document-node()" >
<xsl:document>
<xsl:element name="p0">
<p1 aaa='AAA' />
</xsl:element>
</xsl:document>
</xsl:function>
И полное преобразование было бы:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:sequence select="my:ggg()"/>
</xsl:template>
<xsl:function name="my:fff" as="document-node()" >
<xsl:document>
<xsl:element name="p0">
<p1 aaa='AAA' />
</xsl:element>
</xsl:document>
</xsl:function>
<xsl:function name="my:ggg">
<xsl:variable name="v" select="my:fff()" />
<!-- Debug messages -->
<xsl:message>
$v '
<xsl:sequence select="$v" />
' $v/* '
<xsl:sequence select="$v/*" />
' $v/*/@aaa '
<xsl:value-of select="$v/*/@aaa" />
' $v/p0 '
<xsl:sequence select="$v/p0" />'
</xsl:message> ...
</xsl:function>
</xsl:stylesheet>
затем, применяя это преобразование к любому XML-документу (не используется), теперь получается следующий отладочный вывод:
$v '<p0><p1 xmlns:my="my:my" aaa="AAA"/></p0>'
$v/* '<p0><p1 xmlns:my="my:my" aaa="AAA"/></p0>'
$v/*/@aaa ''
$v/p0 '<p0><p1 xmlns:my="my:my" aaa="AAA"/></p0>'
вероятно, это то, что вы хотите, за исключением aaa
атрибута, к которому необходимо обращаться как: $v/*/*/@aaa
Ответ №2:
$v
элемент, возвращаемый с помощью my:fff
, поэтому он является тегом <p0>
, включающим дочерние элементы. $v/p0
пытается выбрать a <p0>
в качестве дочернего тега в $v
, который пуст, поскольку тег, <p0>
выбранный $v
, не содержит a <p0>
.
Ответ №3:
Вам было бы легче диагностировать такого рода проблемы, если бы вы взяли за привычку всегда объявлять типы аргументов и возвращаемых значений функции. Это заставило бы вас задуматься о том, что возвращает my:fff. В данном случае это элемент node (без родительских элементов): вы можете объявить результат как as="element(p0)"
. Тогда было бы гораздо очевиднее, что элемент p0 вряд ли будет иметь дочерних элементов p0, так что my:fff()/p0
, вероятно, это неправильно.