Home > front end >  Determine if xml nodes has same ancestor
Determine if xml nodes has same ancestor

Time:05-10

[xml] $xml = "<TOP>
    <A>
        <X><match>yes</match></X>
        <X><match>yes</match></X>
        <Y><match>yes</match></Y>
    </A>
    <B>
        <X><match>yes</match></X>
        <Z><match>yes</match></Z>
    </B>
</TOP>"

$matches = $xml.SelectNodes("//match")
$previous = ""
foreach($match in $matches)
{
    $current = $match.ParentNode.ParentNode.Name
    if($current -eq $previous)
    {
        write-host "Same ancestor!:" $match.ParentNode.ParentNode.OuterXml
    }
    $previous = $match.ParentNode.ParentNode.Name 
}

Using xpath and powershell I find all matching nodes, but also want to determine if the nodes have the same ancestors X level op. In the example I have compared 2 level up and only for 2 nodes (current and previous) at the time. I believe there is a better solution using xpath, when looping the matches

I have tried using something like /TOP/A[//X[1]/match][//X[2]/match] but is stuck

Basically I want to tell that of the 5 matching nodes 3 share the same ancestor whereas the last 2 node share the same ancestor.

CodePudding user response:

You should not compare the names, you should compare the nodes themselves.

$xml = [xml]"<TOP>
    <A>
        <X><match>yes</match></X>
        <X><match>yes</match></X>
        <Y><match>yes</match></Y>
    </A>
    <A>
        <X><match>yes</match></X>
        <Z><match>yes</match></Z>
    </A>
</TOP>"

$matches = $xml.SelectNodes("//match")

foreach ($match in $matches)
{
    $current = $match.ParentNode.ParentNode
    if ($current -eq $previous)
    {
        write-host "Same ancestor!:" $current.OuterXml
    }
    else
    {
        write-host "Different ancestor!:" $current.OuterXml
    }
    $previous = $current
}

prints

Different ancestor!: <A><X><match>yes</match></X><X><match>yes</match></X><Y><match>yes</match></Y></A>
Same ancestor!: <A><X><match>yes</match></X><X><match>yes</match></X><Y><match>yes</match></Y></A>
Same ancestor!: <A><X><match>yes</match></X><X><match>yes</match></X><Y><match>yes</match></Y></A>
Different ancestor!: <A><X><match>yes</match></X><Z><match>yes</match></Z></A>
Same ancestor!: <A><X><match>yes</match></X><Z><match>yes</match></Z></A>

CodePudding user response:

If I've understood correctly, Consider

count($a/ancestor::X | $b/ancestor::X) = 1

to test if $a and $b have the same X ancestor.

From XPath 2.0 there is an "is" operator to make this simpler

$a/ancestor::X is $b/ancestor::X
  • Related