Как обратиться к значению дочернего элемента текущего узла при выборе другого узла с XPath? (Связанный с DDEX)

Рассмотрим эту XML-структуру, упрощенную версию стандарта DDEX:

<doc>
<master>
 <ResourceInfo>
  <Name>Foo</Name>
  <Seq>1</Seq>
 </ResourceInfo>
 <ResourceInfo>
  <Name>Bar</Name>
  <Seq>2</Seq>
 </ResourceInfo>
</master>
<track>
 <Resource>
  <Name>Foo</Name>
 </Resource>
</track>
<track>
 <Resource>
  <Name>Bar</Name>
 </Resource>
</track>
</doc>

Я хотел бы выбрать узел ResourceInfo в <master> с ребенком <Name> сопоставляя текстовое значение имени каждого из узлов трека, чтобы получить номер Seq.

Я могу сделать это напрямую, получая дерево lxml каждой дорожки и явно запрашивая <ResourceInfo>вот так:

track.xpath('/doc/master/ResourceInfo/Seq[../Name[text()="Foo"]]')

Но это предполагает, что я знаю название каждого трека и могу явно указать его заранее. Я хотел бы иметь возможность тупо отобразить это и каким-то образом заменить "Foo" в xpath с некоторой ссылкой на имя text() ресурса текущего трека.

Это своего рода объединение треков и ресурсов на text() Имени в мастере с text() имени в каждой дорожке. Есть ли простой способ сделать это с XPath?

Я пытаюсь перебрать каждый трек и вытащить Seq с трека. Поэтому я не могу явно попросить "Foo". Мне нужно самоанализ - "Дайте мне Seq, который является братом <Name> узел в мастере с сопоставлением значений <Name> текущего узла в <track>".

2 ответа

Я не уверен, что я полностью понимаю, но если текущий контекст:

/doc/track/Resource/Name

и вы используете следующий XPath:

/doc/master/ResourceInfo[Name = current()]/Seq

Вы должны получить Seq из ResourceInfo того же самого Name,

Прочитав ваш комментарий, я теперь понимаю, что вы после. Вы можете просто использовать Python для соединения:

from lxml import etree

doc = etree.parse('sample.xml')

# gather resources
resources = {}
for element in doc.xpath('/doc/master/ResourceInfo'):
    name = element[0].text
    seq  = element[1].text
    resources[name] = seq

# gather tracks
tracks = []
for element in doc.xpath('/doc/track/Resource/Name'):
    name = element.text
    tracks.append(name)

# join:

for track in tracks:
    print 'Track: %s, seq: %s' % (track, resources.get(track))

# returns: 
# Track: Foo, seq: 1
# Track: Bar, seq: 2

Предыдущий ответ:

XML не был правильно сформирован:

<doc>
  <master>
    <ResourceInfo>
      <Name>Foo</Name>
      <Seq>1</Seq>
    </ResourceInfo>
    <ResourceInfo>
      <Name>Bar</Name>
      <Seq>2</Seq>
    </ResourceInfo>
  </master>
  <track>
    <Resource>
      <Name>Foo</Name>
    </Resource>
  </track>  <!-- was missing backslash -->
  <track>
    <Resource>
      <Name>Bar</Name>
    </Resource>
  </track>
</doc>

Ваш код работает:

from lxml import etree

doc = etree.parse('a.xml')

for element in doc.xpath('/doc/master/ResourceInfo/Seq[../Name[text()="Foo"]]'):
    #print etree.tostring(element)
    print element.text  

# returns
# 1
Другие вопросы по тегам