简体   繁体   中英

XPath to produce a result node-set containing the same node more than once?

What I tried to say in the title is:

Given a bit of XML in which I know a particular element appears only once, is it possible using a single XPath query to select a node-set that contains that element twice?

I understand there's a "union" operator (|) but that's basically a logical-OR, right? In SQL terms I'm looking then for the equivalent of a "union all".

Eg Given the XML fragment...

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

...is there a query that will get me a result set equivalent to...

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

I haven't found anything that makes me think it can be done - but that's why I'm asking...

As pointed in the other answers, XPath cannot modify an XML document and produce new nodes .

Any node can participate in a node-set only once, due to the definition of "set" .

However, XPath 2.0 gives us the new sequence type , which allows items to be repeated.

In order to have an element appearing twice in a sequence, one would just use the sequence concatenation operator "," as in the below expression:

/*/ElementYouWant, /*/ElementYouWant

Put this into an XSLT2.0 stylesheet as simple as this:

<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>

And apply this transformation on this XML document:

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

to produce the wanted result:

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

Do note, that if one uses the <xsl:sequence> instruction, no new copy of the <ElementYouWant> element is created -- therefore in XSLT 2.0 it is recommended to use <xsl:sequence> and to avoid using <xsl:copy-of> which creates (unnecessary) copies of nodes.

XPath gives you node- sets , so by definition nodes appear only once. Now, you can have named template and call it twice with same 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>

XPath is a language to query the data within an XML document while the SQL UNION ALL syntax combines resultsets from two different queries.

XPath by itself cannot be used to present the existing data in a format that does not match the existing format. However, you could use XSLT to perform this transformation:

<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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM