Xpath to select all and exclude child and its chil

2020-06-17 15:14发布

问题:

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

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?

回答1:

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



回答2:

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.