1
votes

My example XML is as follows:

<FileList>
  <File>
    <Name>20120427_1.pdf</Name>
    <Size>654441</Size>
    <Property>
      <Name>Country</Name>
      <Value>United States</Value>
    </Property>
   </File>
   <File>
    <Name>Name2</Name>
    <Size>2147483647</Size>
    <Property>
      <Name>Name4</Name>
      <Value>Value4</Value>
    </Property>
    <Property>
      <Name>Name5</Name>
      <Value>Value5</Value>
    </Property>
    <Property>
      <Name>Name6</Name>
      <Value>Value6</Value>
    </Property>
  </File>
  <File>
    <Name>Name3</Name>
    <Size>2147483647</Size>
    <Property>
      <Name>Name7</Name>
      <Value>Value7</Value>
    </Property>
    <Property>
      <Name>Name8</Name>
      <Value>Value8</Value>
    </Property>
    <Property>
      <Name>Country</Name>
      <Value>UK</Value>
    </Property>
  </File>
</FileList>

The requirement is that every file node has a Country value in the Propery/Name element. So far I've created an XPath query:

/FileList/File/Property/Name/text()='Country'

This passes as true as query is looking at all nodes when the answer should be false. How do I change it so it checks each 'File' node instead?

2

2 Answers

1
votes

Use:

not(/*/File[not(Property/Name = 'Country')])

XSLT - based verification:

This transformation:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:copy-of select=
     "not(/*/File[not(Property/Name = 'Country')])"/>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<FileList>
  <File>
    <Name>20120427_1.pdf</Name>
    <Size>654441</Size>
    <Property>
      <Name>Country</Name>
      <Value>United States</Value>
    </Property>
   </File>
   <File>
    <Name>Name2</Name>
    <Size>2147483647</Size>
    <Property>
      <Name>Name4</Name>
      <Value>Value4</Value>
    </Property>
    <Property>
      <Name>Name5</Name>
      <Value>Value5</Value>
    </Property>
    <Property>
      <Name>Name6</Name>
      <Value>Value6</Value>
    </Property>
  </File>
  <File>
    <Name>Name3</Name>
    <Size>2147483647</Size>
    <Property>
      <Name>Name7</Name>
      <Value>Value7</Value>
    </Property>
    <Property>
      <Name>Name8</Name>
      <Value>Value8</Value>
    </Property>
    <Property>
      <Name>Country</Name>
      <Value>UK</Value>
    </Property>
  </File>
</FileList>

evaluates the XPath expression and produces the wanted, correct result:

false

Explanation:

Use of the double negation law.

0
votes

To get a File without a Country, use

/FileList/File[not(Property[Name='Country'])]

To only get its name, you can use

/FileList/File[not(Property[Name='Country'])]/Name/text()