XPath возвращает значение по умолчанию, если node нет
Скажем, у меня есть пара XML-документов
<Foo>
<Bar/>
<Baz>mystring</Baz>
</Foo>
и
<Foo>
<Bar/>
</Foo>
Мне нужен XPath (только версия 1.0), который возвращает "mystring" для первого документа и "не найден" для второго. Я попробовал
(string('not-found') | //Baz)[last()]
но левая сторона объединения не является node -set
Ответы
Ответ 1
В XPath 1.0 используйте:
concat(/Foo/Baz,
substring('not-found', 1 div not(/Foo/Baz)))
Если вы хотите обработать допустимый пустой элемент Baz
, используйте:
concat(/Foo/Baz,
substring('not-found', 1 div not(/Foo/Baz[node()])))
С помощью этого ввода:
<Foo>
<Baz/>
</Foo>
Результат: not-found
строковый тип данных.
Ответ 2
@Alejandro предоставил лучший ответ XPath 1.0, который был известен годами, поскольку впервые использовавшийся Jeni Tennison почти десять лет назад.
Единственная проблема с этим выражением - это блестящая элегантность, которая затрудняет понимание не только начинающих программистов.
В размещенном XPath 1.0 (и каждый XPath размещен!) можно использовать более понятные выражения:
string((/Foo/Baz | $vDefaults[not(/Foo/Baz/text())]/Foo/Baz)[last())
Здесь переменная $vDefaults
представляет собой отдельный документ, который имеет ту же структуру, что и основной XML-документ, а текстовые узлы которого содержат значения по умолчанию.
Или, если XSLT является языком хостинга, можно использовать функцию document()
:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
<xsl:output method="text"/>
<my:defaults>
<Foo>
<Bar/>
<Baz>not-found</Baz>
</Foo>
</my:defaults>
<xsl:template match="/">
<xsl:value-of select=
"concat(/Foo/Baz,
document('')[not(current()/Foo/Baz/text())]
/*/my:defaults/Foo/Baz
)"/>
</xsl:template>
</xsl:stylesheet>
Или, не используя concat()
:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
<xsl:output method="text"/>
<my:defaults>
<Foo>
<Bar/>
<Baz>not-found</Baz>
</Foo>
</my:defaults>
<xsl:variable name="vDefaults" select="document('')/*/my:defaults"/>
<xsl:template match="/">
<xsl:value-of select=
"(/Foo/Baz
| $vDefaults/Foo/Baz[not(current()/Foo/Baz/text())]
)
[last()]"/>
</xsl:template>
</xsl:stylesheet>
Ответ 3
Специальный случай:
Если вы хотите получить 0, если числовое число node отсутствует или пустое, используйте функцию "sum (/Foo/Baz)"
Ответ 4
/Foo/(Baz/string(), 'not-found')[1]