Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xpath to select all and exclude child and its children

I have the Data below and I am trying to select all the nodes except RejectedRecords and all of its children.

<?xml version="1.0" encoding="UTF-8"?>
<inmsg>
  <BPDATA>
    <DATE_TIME>10072014084945</DATE_TIME>
  </BPDATA>
  <Orders>
    <Rejected>
      <RejectedRecords>
        <RecordNumber>1</RecordNumber>
        <RecordError>State Code is invalid</RecordError>
      </RejectedRecords>
      <RejectedRecords>
        <RecordNumber>2</RecordNumber>
        <RecordError>State Code is invalid</RecordError>
      </RejectedRecords>
      <FileName>Foo1.txt</FileName>
      <MessageType>Rejected</MessageType>
      <RecordCount>2</RecordCount>
      <TotalAmount>1050.01</TotalAmount>
    </Rejected>
    <Unrestricted>
      <FileName>Foo2.txt</FileName>
      <MessageType>UnrestrictedState</MessageType>
      <RecordCount>2</RecordCount>
      <TotalAmount>100.10</TotalAmount>
    </Unrestricted>
  </Orders>
  <PrimaryDocument SCIObjectID="6442821469081a3a3node1"/>
</inmsg>

I have tried a number of statements such as

//*/node()[not(parent::RejectedRecords) and not(self::RejectedRecords) and not(self::RecordNumber) and not(self::RecordError)]
//*[not(parent::RejectedRecords) and not(self::RejectedRecords)]
//*[not(descendant-or-self::RejectedRecords)]

Results

No matter what I have used I am still getting the RejectedRecords node and its children because it is coming in with the Rejected node. What am I doing wrong?

like image 394
camarokris Avatar asked Jun 12 '14 15:06

camarokris


Video Answer


2 Answers

This expression selects all nodes, but does not include in the result set any nodes that are RejectedRecords or that have RejectedRecords as an ancestor:

//*[not(descendant::RejectedRecords) and not(ancestor-or-self::RejectedRecords)]

Here is a link to the result in XPath Tester

like image 135
helderdarocha Avatar answered Oct 02 '22 10:10

helderdarocha


XPath can only select whole subtrees, not change them or create new XML output.

If you select the //Orders element, it will always include the <Rejected/> ones. All you can do is eg. select all orders not rejected, but at the same time you will lose the nodes around:

//Orders/*[not(self::Rejected)]

Depending on how you use XPath, you might use it to actually delete the <Rejected/> elements by selecting them using XPath and then deleting it with the XML framework of your primary programming language.

If you want to create new results from an XML language, you have to use XSLT templates or XQuery (which is very close at XPath). Which better fits your problem depends on your actual requirements and needs.

like image 32
Jens Erat Avatar answered Oct 02 '22 09:10

Jens Erat