XPath для создания результирующего набора узлов, содержащего один и тот же узел более одного раза?

В названии я попытался сказать:

Учитывая фрагмент XML, в котором я знаю, что конкретный элемент появляется только один раз, возможно ли с помощью одиночного запроса XPath выбрать набор узлов, содержащий этот элемент дважды?

Я понимаю, что есть оператор «объединения» (|), но это, по сути, логическое ИЛИ, верно? В терминах SQL я ищу эквивалент «объединить все».

Например. Учитывая фрагмент XML ...

<toplevel>
  <ElementIWant>
    <SomeSubElement1>specific data</SomeSubElement1>
    <SomeSubElement2>specific data 2</SomeSubElement2>
  </ElementIWant>
</toplevel>

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

<ElementIWant>
  ...identical content...
</ElementIWant>
<ElementIWant>
  ...identical content...
</ElementIWant>

Я не нашел ничего, что заставляло бы меня думать, что это возможно - но поэтому я спрашиваю ...


person mwardm    schedule 03.04.2009    source источник


Ответы (3)


XPath предоставляет наборы узлов, поэтому по определению узлы появляются только один раз. Теперь вы можете присвоить шаблону имя и вызвать его дважды с одним и тем же XPath.

<xsl:template match="/ElementIWant"> 
  <xsl:call-template name="repeat"/>
  <xsl:call-template name="repeat"/>
</xsl:template>

<xsl:template name="repeat"> 
  <xsl:copy select=".">
    <xsl:text>... same content ...</xsl:text>
  </xsl:copy>
</xsl:template>
person vartec    schedule 03.04.2009
comment
ну, это единственный способ сделать это ;-) - person vartec; 03.04.2009
comment
Ура (оба). В следующий раз я постараюсь вспомнить, что иногда терминология помогает нам! - person mwardm; 03.04.2009

Как указано в других ответах, XPath не может изменять XML-документ и создавать новые узлы.

Любой узел может участвовать в наборе узлов только один раз, согласно определению "set".

Однако XPath 2.0 предоставляет нам новый тип последовательности, < / strong>, который позволяет повторять элементы.

Чтобы элемент появлялся дважды в последовательности, можно просто использовать < strong> оператор конкатенации последовательностей ",", как в приведенном ниже выражении:

/*/ElementYouWant, /*/ElementYouWant

Поместите это в таблицу стилей XSLT2.0 так просто:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:f="http://fxsl.sf.net/"
 exclude-result-prefixes="f xs"
 >

 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
   <t>
     <xsl:sequence select=
      "/*/ElementYouWant, /*/ElementYouWant"/>
   </t>
 </xsl:template>
</xsl:stylesheet>

И примените это преобразование к этому XML-документу:

<toplevel>
    <ElementYouWant>
        <SomeSubElement1>specific data</SomeSubElement1>
        <SomeSubElement2>specific data 2</SomeSubElement2>
    </ElementYouWant>
</toplevel>

для получения желаемого результата:

<t>
   <ElementYouWant>
            <SomeSubElement1>specific data</SomeSubElement1>
            <SomeSubElement2>specific data 2</SomeSubElement2>
      </ElementYouWant>
   <ElementYouWant>
            <SomeSubElement1>specific data</SomeSubElement1>
            <SomeSubElement2>specific data 2</SomeSubElement2>
      </ElementYouWant>
</t>

Обратите внимание: если вы используете <xsl:sequence> , новая копия элемента <ElementYouWant> не создается - поэтому в XSLT 2.0 рекомендуется использовать <xsl:sequence> и избегать использования <xsl:copy-of>, который создает (ненужные) копии узлов.

person Dimitre Novatchev    schedule 03.04.2009
comment
Дам, мне придется заново изучать xpath. :) спасибо за предупреждение. - person paulmurray; 04.04.2009

XPath - это язык для запроса данных в документе XML, в то время как синтаксис SQL UNION ALL объединяет наборы результатов из двух разных запросов.

Сам по себе XPath нельзя использовать для представления существующих данных в формате, который не соответствует существующему формату. Однако вы можете использовать XSLT для выполнения этого преобразования:

<x:stylesheet version="1.0" xmlns:x="http://www.w3.org/1999/XSL/Transform">
  <x:output method="xml"/>

  <x:template match="/">
    <topMostLevel>
      <x:apply-templates />
    </topMostLevel>
  </x:template>

  <x:template match="toplevel">
    <x:copy-of select="."/>
    <x:copy-of select="."/>
  </x:template>
</x:stylesheet>
person Cerebrus    schedule 03.04.2009