Как получить значение узла, используя переменное имя узла? - PullRequest
2 голосов
/ 03 февраля 2012

У меня есть XML-документ вроде:

<data>
    <item type="apple">
        <misc>something</misc>
        <appleValue>23</appleValue>
        <misc2>something else</misc2>
    </item>
    <item type="banana">
        <bananaValue>47</bananaValue>
        <random>something</random>
    </item>
</data>

Я могу получить элементы с doc("data.xml")/data/item, но мне нужно получить текст из элементов, которые заканчиваются на Value. Поэтому я хотел бы получить «23» и «47», но я не обязательно знаю имена элементов, то есть все, что я действительно знаю, это элементы, которые заканчиваются на Value, я не знаю, если это appleValue, bananaValue и т. Д., За исключением того, что я мог посмотреть на атрибут type и создать строку.

let $type := (doc("data.xml")/data/item)[1]/@type
doc("data.xml")/data/item/$typeValue

... Эта последняя строка - это то, к чему я стремлюсь, очевидно, это не правильно, но мне нужно найти элементы, чье имя известно на основе переменной (хранящейся в переменной, такой как $type) и " Значение».

Есть идеи? Я понимаю, что присвоение имен переменным элементам странно / странно / плохо ... но так оно и есть, и я должен с этим справиться.

Ответы [ 4 ]

2 голосов
/ 03 февраля 2012

Я бы не стал использовать функцию name() в пользу node-name() или local-name().Причина этого в том, что name() может дать вам разные ответы в зависимости от того, какие (и будут ли) префиксы пространства имен используются в источнике.Например, следующие три элемента имеют одинаковое точное имя (QName):

<appleValue xmlns="http://example.com"/>
<x:appleValue xmlns:x="http://example.com"/>
<y:appleValue xmlns:y="http://example.com"/>

Однако функция name() даст вам разные ответы для каждого из них (appleValue, x:appleValuey:appleValue соответственно).Поэтому лучше либо игнорировать пространство имен, используя local-name() (который возвращает строку appleValue для всех трех вышеупомянутых случаев), либо явно указав пространство имен (даже если оно пустое, как показал Оливер), используя node-name() (который возвращает правильное значение QName, а не строку).В этом случае, поскольку вы не используете пространства имен (и, даже если вы добавите его позже, код все равно будет работать), я бы немного высказался за использование local-name() следующим образом:

doc("data.xml")/data/item/*['Value' eq substring-after(local-name(),../@type)]

Для уточнения причин, по которым следует избегать функции name() (и исключений), см. «Опасности функции имени» .

1 голос
/ 03 февраля 2012

Вы можете получить доступ к имени узла, используя name(). XPath 1.0 не имеет функции «заканчивается», но с помощью substring() и string-length() - 1 вы можете получить ее.

//item/*[ substring(  name(),  string-length(name() ) - 4  ) = 'Value']
1 голос
/ 03 февраля 2012

Я получил это благодаря этому сообщению: Может ли XPath совпадать по частям имени элемента?

doc("data.xml")/data/item/*[ends-with(name(), "Value")]
0 голосов
/ 03 февраля 2012

Более точный способ реализовать это будет

for $item in doc("data.xml")/data/item
let $value-name := fn:QName('', concat($item/@type, 'Value'))
return $item/*[node-name() = $value-name]
...