vik santata
vik santata

Reputation: 3109

Powershell: how to use xpath to filter by attribute and content at the same time?

I have this script:

function f3
{
[xml]$xml = @"
<?xml version="1.0" encoding="utf-8"?>
<Book>
  <projects>
    <project name="Book1" date="2009-01-20">
      <editions>
        <edition language="English">Novel_1</edition>
        <edition language="English">my.Book1.com</edition>
        <edition language="German">Ge.Book1.Com</edition>
        <edition language="French">Fr.Book1.com</edition>
        <edition language="Polish">Pl.Book1.com</edition>
        <edition language="English">Novel_2</edition>
        <edition language="English">FairyTale</edition>
      </editions>
    </project>
  </projects>
</Book>
"@

$xml.SelectNodes("/Book/projects/editions")
}
f3

I wish to select "language=English", with content either contains "Novel" or equals "FairyTale", so my expected output is:

Novel_1
Novel_2
FairyTale

So how can I change my "SelectNodes" statement? Thanks a lot!

Upvotes: 3

Views: 6580

Answers (2)

har07
har07

Reputation: 89305

In xpath, you can combine multiple boolean values using standard boolean operators like or and and :

/Book/*/*/*/edition[@language='English' and (.='FairyTale' or contains(.,'Novel'))]

alternatively, separating and operands into two predicates ([]) :

/Book/*/*/*/edition[@language='English'][.='FairyTale' or contains(.,'Novel')]

For this case, you may also want to consider using starts-with() function instead of contains() to be more precise.

side note : * is just my way to shorten the xpath expression to fit in one line without having to reduce efficeincy (f.e using // axis like /Book//edition), you are fine to use the actual element names in place of *.

Upvotes: 3

Jason W
Jason W

Reputation: 13179

The solution below updates the xpath to the editions element, then applies the where to filter as you requested.

$xml.SelectNodes("/Book/projects/project/editions/edition") `
    | Where-Object { $_.language -eq "English" } `
    | Where-Object { $_."#text" -like "*novel*" -or $_."#text" -eq "FairyTale" } `
    | Format-Table @{Expression={$_."#text"};Label="Novel"}

Upvotes: 2

Related Questions