2012-02-03 3 views
2

У меня есть 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) и «Значение».

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

ответ

1

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

//item/*[ substring( name(), string-length(name()) - 4 ) = 'Value'] 
0

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

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

Я хотел бы избежать с помощью функции 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:appleValue и y:appleValue, соответственно). Таким образом, вам лучше игнорировать пространство имен, используя local-name() (который возвращает строку appleValue для всех трех случаев) или явно указывая пространство имен (даже если оно пустое, как показал Оливер), используя node-name() (который возвращает правильное QName, а не строка). В этом случае, так как вы не используете пространство имен (и, так как даже если вы добавили один позже, этот код будет работать), я бы немного в пользу использования local-name() следующим образом:

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

Для разработки по причинам, чтобы избежать функции name() (и исключений), см. "Perils of the name function".

Смежные вопросы