Thats  Enough
Thats Enough

Reputation: 25

XPath expression to exclude some child nodes

I have this source XML tree:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <foo>
    <bar>
      <baz>
        <item>
          <methods>
            <item>
              <id>1</id>
            </item>
          </methods>
          <id>1</id>
        </item>
        <item>
          <methods>
            <item>
              <id>19</id>
            </item>
          </methods>
          <id>2</id>
        </item>
      </baz>
    </bar>
  </foo>
  <bar_method>
    <root>
      <bla id="1">
        <methods>
          <method id="1">
            <calc md="ck" />
            <tm m="14" />
            <price_list>
              <price mse="0">
                <ins re="0" />
              </price>
            </price_list>
          </method>
          <method id="2">
            <calc md="qck" />
            <tm m="4" />
            <price_list>
              <price mse="1">
                <ins re="0" />
              </price>
            </price_list>
          </method>
        </methods>
      </bla>
      <bla id="2">
        <methods>
          <method id="19">
            <calc md="dd" />
            <tm m="3" />
            <price_list>
              <price mse="01">
                <ins re="0" />
              </price>
            </price_list>
          </method>
        </methods>
      </bla>
    </root>
  </bar_method>
</root>

Now I need to place fragment of this tree in variable using XPath. The fragment should look like this:

<bla id="1">
  <methods>
    <method id="1">
      <calc md="ck" />
      <tm m="14" />
      <price_list>
        <price mse="0">
          <ins re="0" />
        </price>
      </price_list>
    </method>
  </methods>
</bla>
<bla id="2">
  <methods>
    <method id="19">
      <calc md="dd" />
      <tm m="3" />
      <price_list>
        <price mse="01">
          <ins re="0" />
        </price>
      </price_list>
    </method>
  </methods>
</bla>

These are bla nodes excluding method nodes, id attributes of which missing in /root/foo/bar/baz/item/methods/item/id. I use following expression but it selects all nodes with duplicates:

<xsl:variable name="meth" select="/root/bar_method/root//*[not(name() = 'method' and count(/root/foo/bar/baz//methods/item[id = @id]) = 0)]" />

Upvotes: 0

Views: 900

Answers (2)

Michael Kay
Michael Kay

Reputation: 163595

XPath can only select nodes, it cannot change them. That is to say, the children and descendants of the nodes you select will always be exactly as they were in the source document.

If you want to create a tree that's different from the input tree, you need XSLT or XQuery.

Upvotes: 1

Borodin
Borodin

Reputation: 126762

Looks like you want all the bla elements and just the first methods/method element within each of them. Is that right?

You can't do that in a single XPath expression because you can only restrict the elements being selected - you can't filter out some of their descendants as well. But it is possible using templates.

This stylesheet creates the variable $meth and outputs it using copy-of.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:strip-space elements="*"/>
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

  <xsl:template match="/">
    <xsl:variable name="meth">
      <xsl:apply-templates select="root/bar_method/root/bla"/>
    </xsl:variable>
    <xsl:copy-of select="$meth"/>
  </xsl:template>

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="methods">
    <xsl:copy>
      <xsl:apply-templates select="method[1]"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

output

<bla id="1">
   <methods>
      <method id="1">
         <calc md="ck"/>
         <tm m="14"/>
         <price_list>
            <price mse="0">
               <ins re="0"/>
            </price>
         </price_list>
      </method>
   </methods>
</bla>
<bla id="2">
   <methods>
      <method id="19">
         <calc md="dd"/>
         <tm m="3"/>
         <price_list>
            <price mse="01">
               <ins re="0"/>
            </price>
         </price_list>
      </method>
   </methods>
</bla>

Upvotes: 0

Related Questions