0

input xml

<?xml version='1.0' encoding='UTF-8'?>
<Report>
    <Employee State="A">
        <Information>
            <Data Name="Rank">SM1</Data>
            <Data Name="City">CA</Data>
        </Information>
    </Employee>
    <Employee State="B">
        <Information>
            <Data Name="Rank">SM2</Data>
            <Data Name="City">CA</Data>
        </Information>
    </Employee>
    <Employee State="A">
        <Information>
            <Data Name="Rank">SM3</Data>
            <Data Name="City">CB</Data>
        </Information>
    </Employee>
    <Employee State="D"/>
    <Information>
        <Data Name="Rank">SM1</Data>
    </Information>
</Report>

I want to get all "Employee" nodes which are previous to Employee node having "State" attribute value as "D" and whose "Data" element value for which "Name" attributes value is "Rank", is either SM1 or SM2

That means for above input I want output like:

<Employee State="A">
        <Information>
            <Data Name="Rank">SM1</Data>
            <Data Name="City">CA</Data>
        </Information>
    </Employee>
    <Employee State="B">
        <Information>
            <Data Name="Rank">SM2</Data>
            <Data Name="City">CA</Data>
        </Information>
    </Employee>

I am using path expression as

/Report/Employee[@State='D']/preceding-sibling::Employee/Information[Data[@Name='Rank']/text()='SM1' or text()='SM2']

I also tried to use

/Report/Employee[@State='D']/preceding-sibling::Employee/Information[Data[@Name='Rank']/text()='SM1' or 'SM2']

I got related question

but it looks like that syntax is valid for attribute value and not the element values, that syntax did not work either.

1 Answers1

1

Firstly, it's unnecessary, and bad practice, to use text() to get the string value of an element node.

Secondly, you need to tell us which version of XPath you are using, since 1.0, 2.0 and 3.1 are all in common use.

In 2.0+, you can write

/Report/Employee[@State='D']/preceding-sibling::Employee
   [Information[Data[@Name='Rank']=('SM1','SM2')]]

In 1.0, it's

/Report/Employee[@State='D']/preceding-sibling::Employee
   [Information[Data[@Name='Rank'][.='SM1' or .='SM2']]]

Note that this returns the Employee elements, as requested, whereas your attempts are returning the Information elements.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • Thanks @Michael Kay. For the people who would like to refer to 1.0 expression, One closing bracket is missing here, just to save your 2-3 mins :-) – Vineet Dwivedi Jul 03 '21 at 10:40