70

I need an XPath to fetch all ChildNodes ( including Text Element, Comment Element & Child Elements ) without Parent Element. Any help

Sample Example:

<DOC>
<PRESENTEDIN>
    <X>
        First Text Node #1 
        <y> Y can Have Child Nodes # 
            <child> deep to it </child> 
         </y>
         Second Text Node #2 <z/> 
    </X>
    <EVTS>
        <evt/>
        <evt>
            <mtg_descr> SAE 2006 World Congress &amp; Exhibition </mtg_descr>
            <sess_descr> Advanced Hybrid Vehicle Powertrains (Part 1 of 5) </sess_descr>
            <loc> Detroit,MI,United States </loc>
            <sess_prod_grp_cd> TSESS </sess_prod_grp_cd>
            <sess_evt_name> P13 </sess_evt_name>
            <sess_gen_num> 138352 </sess_gen_num>
            <mtg_start_dt> 04/03/2006 </mtg_start_dt>
            <mtg_end_dt> 04/06/2006 </mtg_end_dt>
            <desig> CONGRESS-2006 </desig>
        </evt>
    </EVTS>
    <EVTTYPE>PAPER</EVTTYPE>
    <SUPERTECH>
        <![CDATA[C8585]]>
    </SUPERTECH>
</PRESENTEDIN>

XPATH TRIED

   1. $doc/PRESENTEDIN/X
   2. $doc/PRESENTEDIN/X/descendant::*
   2. $doc/PRESENTEDIN/X/self::*

EXPECTED OUTPUT

    First Text Node #1 
    <y> Y can Have Child Nodes # 
        <child> deep to it </child> 
     </y>
     Second Text Node #2 <z/> 

I DON'T WANT

<X>
  First Text Node #1 
        <y> Y can Have Child Nodes # 
            <child> deep to it </child> 
         </y>
         Second Text Node #2 <z/> 
</X>
David Moles
  • 48,006
  • 27
  • 136
  • 235
kadalamittai
  • 2,076
  • 1
  • 16
  • 19

2 Answers2

89

From the documentation of XPath ( http://www.w3.org/TR/xpath/#location-paths ):

child::* selects all element children of the context node

child::text() selects all text node children of the context node

child::node() selects all the children of the context node, whatever their node type

So I guess your answer is:

$doc/PRESENTEDIN/X/child::node()

And if you want a flatten array of all nested nodes:

$doc/PRESENTEDIN/X/descendant::node()
linepogl
  • 9,147
  • 4
  • 34
  • 45
  • 1
    Correct but do also check the [Abbreviated Syntax](http://www.w3.org/TR/xpath/#path-abbrev) –  Feb 25 '11 at 16:49
  • 1
    I'm using this to copy all child nodes, but on the output each child element is stamped with a namespace identifier; any way to disable that? – raffian Feb 01 '12 at 20:22
  • Also, the slash before "child::" indicates one level down, two slashes indicates more than one level down. – urbanaut Oct 21 '16 at 19:38
28

Use this XPath expression:

/*/*/X/node()

This selects any node (element, text node, comment or processing instruction) that is a child of any X element that is a grand-child of the top element of the XML document.

To verify what is selected, here is this XSLT transformation that outputs exactly the selected nodes:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>
 <xsl:template match="/">
  <xsl:copy-of select="/*/*/X/node()"/>
 </xsl:template>
</xsl:stylesheet>

and it produces exactly the wanted, correct result:

   First Text Node #1            
    <y> Y can Have Child Nodes #                
        <child> deep to it </child>
    </y>            Second Text Node #2 
    <z />

Explanation:

  1. As defined in the W3 XPath 1.0 Spec, "child::node() selects all the children of the context node, whatever their node type." This means that any element, text-node, comment-node and processing-instruction node children are selected by this node-test.

  2. node() is an abbreviation of child::node() (because child:: is the primary axis and is used when no axis is explicitly specified).

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431