Получить первый дочерний узел в XSLT, используя local-name()

Предположим, у нас есть этот простой 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

person raffian    schedule 08.11.2011    source источник
comment
Ваш запрос //books[1]/* должен возвращать два элемента книги, а не автора и заголовок. Так что где-то путаница.   -  person Michael Kay    schedule 09.11.2011
comment
Нет, он возвращает только первый с моим трансформером Xalan 1.0 XSLT.   -  person raffian    schedule 09.11.2011
comment
Да, это было моим недостатком в ОП, я использую [1] на основе, спасибо за информацию   -  person user646584    schedule 09.11.2011
comment
@RaffiM: Знаете ли вы, что приняли в целом неверный ответ?   -  person Dimitre Novatchev    schedule 09.11.2011


Ответы (3)


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

//books[1]/*

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

/books/*

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

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

/*/*[1]

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

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

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

person Borodin    schedule 09.11.2011
comment
См. мои правки выше в исходном сообщении для получения более подробной информации о том, чего я пытаюсь достичь, извините за отсутствие дополнительных деталей. Я попытался использовать /*/*[1], он печатает автора, заголовок дважды, мне просто нужно, чтобы он печатался один раз. - person raffian; 09.11.2011

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

So:

//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"/>
person Dimitre Novatchev    schedule 09.11.2011
comment
@RaffiM: Был ли мой ответ полезен для вас? - person Dimitre Novatchev; 09.11.2011

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

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

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

person I_am_an_invited_person    schedule 07.10.2014