XPath для возврата значения по умолчанию, если узел отсутствует - PullRequest
15 голосов
/ 20 декабря 2010

Скажем, у меня есть пара документов XML

<Foo>
    <Bar/>
    <Baz>mystring</Baz>
</Foo>

и

<Foo>
    <Bar/>
</Foo>

Я хочу XPath (только версия 1.0), который возвращает «mystring» для первого документа ине найден »для второго.Я попытался

(string('not-found') | //Baz)[last()]

, но левая часть объединения не является набором узлов

Ответы [ 5 ]

17 голосов
/ 20 декабря 2010

В 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 строковый тип данных.

14 голосов
/ 20 мая 2013

Особый случай: если вы хотите получить 0, если числовой узел отсутствует или пуст, используйте функцию «sum (/ Foo / Baz)»

8 голосов
/ 20 декабря 2010

@ Алехандро предоставил лучший ответ XPath 1.0, который был известен годами с тех пор, как впервые использовался Джени Теннисон почти десять лет назад .

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

В размещенном 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>
1 голос
/ 04 июня 2018

Если вы в порядке с печатью пустой строки вместо сообщения «not-found», используйте:

/Foo/concat(Baz/text(), '')

Позже вы можете заменить пустые строки на "not-found".

1 голос
/ 20 декабря 2010
/Foo/(Baz/string(), 'not-found')[1]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...