Извлечь значение атрибута узла через XPath

270

Как я могу извлечь значение атрибута узла через XPath?

Пример XML-файла:

<parents name='Parents'>
  <Parent id='1' name='Parent_1'>
    <Children name='Children'>
      <child name='Child_2' id='2'>child2_Parent_1</child>
      <child name='Child_4' id='4'>child4_Parent_1</child>
      <child name='Child_1' id='3'>child1_Parent_1</child>
      <child name='Child_3' id='1'>child3_Parent_1</child>
    </Children>
  </Parent>
  <Parent id='2' name='Parent_2'>
    <Children name='Children'>
      <child name='Child_1' id='8'>child1_parent2</child>
      <child name='Child_2' id='7'>child2_parent2</child>
      <child name='Child_4' id='6'>child4_parent2</child>
      <child name='Child_3' id='5'>child3_parent2</child>
    </Children>
  </Parent>
</parents>

Пока у меня есть строка XPath:

//Parent[@id='1']/Children/child[@name]  

Возвращается только child элементы, но я хотел бы иметь значение nameатрибута.

Для моего образца XML-файла вот что я хотел бы получить:

Child_2
Child_4
Child_1
Child_3
Rehman
источник
Возможный дубликат атрибута Getting с использованием XPath
tripleee

Ответы:

351
//Parent[@id='1']/Children/child/@name 

Ваш оригинал child[@name]означает элемент, childкоторый имеет атрибут name. Вы хотите child/@name.

lweller
источник
14
Согласен, вопрос был в том, как получить значение атрибута
Владтн
5
Что, если я хотел бы извлечь только значение / описание / данные, присутствующие между тегами ....
Дину Дьюк
147

Чтобы получить только значение (без имен атрибутов), используйте string():

string(//Parent[@id='1']/Children/child/@name)

Функция fn: string () вернет значение своего аргумента как xs:string. Если его аргумент является атрибутом, он будет возвращать значение атрибута как xs:string.

acdcjunior
источник
1
С xqillaэтим нужно было позвонить xs:string. Интересно, почему.
krlmlr
1
@krlmlr Вероятно, xsэто префикс пространства имен для функций XPath. Поэтому они не перепутаны с другими.
acdcjunior
4
РЖУНИМАГУ. Это единственный ответ, который на самом деле отвечает на вопрос. +1
james.garriss
3
Это даст только первый хит в xmllint
crazyduck
1
Что если у меня есть список атрибутов и мне нужны их значения? Строка (), кажется, возвращает только первое значение.
Дамлуар
9

Вы должны использовать //Parent[@id='1']/Children/child/data(@name)

Атрибуты не могут быть сериализованы, поэтому вы не можете вернуть их в виде XML. Что вам нужно сделать, это получить данные из атрибута с помощью функции data ().

Наталья Мачейовская
источник
9

Как ответили выше:

//Parent[@id='1']/Children/child/@name 

будет выводить только nameатрибут 4 childузлов, принадлежащих Parentуказанному его предикату [@id=1]. Затем вам нужно будет изменить предикат на, [@id=2]чтобы получить набор childузлов для следующего Parent.

Однако, если вы полностью игнорируете Parentузел и используете:

//child/@name

Вы можете выбрать nameатрибут всех childузлов за один раз.

name="Child_2"
name="Child_4"
name="Child_1"
name="Child_3"
name="Child_1"
name="Child_2"
name="Child_4"
name="Child_3"
Винод Шривастав
источник
6
//Parent/Children[@  Attribute='value']/@Attribute

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

Акшай Дубей
источник
3

@ryenus, тебе нужно перебрать результат. Вот как я это сделаю в VBScript;

Set xmlDoc = CreateObject("Msxml2.DOMDocument")
xmlDoc.setProperty "SelectionLanguage", "XPath"
xmlDoc.load("kids.xml")

'Remove the id=1 attribute on Parent to return all child names for all Parent nodes
For Each c In xmlDoc.selectNodes ("//Parent[@id='1']/Children/child/@name")
    Wscript.Echo c.text
Next
NickC
источник
3

для всех xml с пространством имен используйте local-name ()

//*[local-name()='Parent'][@id='1']/*[local-name()='Children']/*[local-name()='child']/@name 
Эд Бангга
источник