Получить первый дочерний узел в XSLT, используя local-name () - PullRequest
6 голосов
/ 09 ноября 2011

Предположим, у нас есть этот простой xml ...

 <books>   
    <book>
       <author/>
       <title/>
    </book>
    <book>
       <author/>
       <title/>
    </book>
 </books>

Я использую этот xpath для получения элементов первого экземпляра книги.

//books[1]/*

Возвращает

<author/>
<title/>

И это прекрасно работает, но я должен заставить его работать, используя local-name ().Я пробовал следующее, но ни одна из этих работ ...

//*[local-name()='books']/*

это возвращает повторяющиеся элементы автора и заголовка, не хорошо, они нужны мне только от первого потомка

//*[local-name()='books'][0]/*

это ничего не возвращает

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

author,title
john,The End is Near
sally,Looking for Answers

Ответы [ 3 ]

12 голосов
/ 09 ноября 2011

Это часто задаваемые вопросы - оператор XPath [] имеет более высокий приоритет (приоритет), чем псевдо-оператор //.

Итак:

//someElemName[1]

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

Чтобы изменить это, необходимо использовать скобки.

Используйте

(//*[local-name() = 'book'])[1]/*

Также обратите внимание : В XPath позиции основаны на 1, а не на 0.

Проверка на основе XSLT:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:copy-of select=
  "(//*[local-name() = 'book'])[1]/*"/>
 </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к следующему документу XML :

<books>
    <book num="1">
        <author num="1"/>
        <title num="1"/>
    </book>
    <book num="2">
        <author num="2"/>
        <title num="2"/>
    </book>
</books>

нужные узлы выбираются и копируются в вывод :

<author num="1"/>
<title num="1"/>
11 голосов
/ 09 ноября 2011

Выражение пути, которое вы говорите, работает для вас

//books[1]/*

создает список всех дочерних узлов первого (и только в этом случае) вхождения любого узла . Поскольку, по вашим данным, единственное вхождение находится в корне, оно совпадает с

/books/*

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

Трудно понять, что вам нужно, так как если вы всегда применяете local-name к корневому узлу, вам не нужно знать его имя и вы можете получить к нему доступ только с помощью /*, так что вы захотите просто

/*/*[1]

Однако, чтобы получить доступ к первому дочернему узлу узла в любом месте документа, вы должны написать

//*[local-name()='books']/*[1]

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

0 голосов
/ 07 октября 2014

Я должен встретить те же проблемы.Я решил следующим образом:

//*[local-name()='MYNODENAME' and position()=X]

Хорошего дня.

...