Search code examples
xmlxpathxquery

Find any element whose value = X and report path to root


I have data like this:

<people>
    <person id="1">
        <july>busy</july>
    </person>
    <person id="2">
        <july>
            <Fridays>busy</Fridays>
        </july>
    </person>
    <person id="3">
        <july>
            <Fridays>
                <afternoons>busy</afternoons>
            </Fridays>
        </july>
    </person>
</people>

I want to to find all elements whose text = 'busy', and then report their paths back to the root.

I haven't even found how to just print elements yet.

//[text() = "busy"]

gives

[false()]
[false()]
[false()]
[true()]
[false()]
[false()]
[false()]
[true()]
[false()]
[false()]
[false()]
[false()]
[true()]
[false()]

//*[. = 'busy']!path() from Martin Honnen comes very close!

/Q{}people[1]/Q{}person[1]
/Q{}people[1]/Q{}person[1]/Q{}july[1]
/Q{}people[1]/Q{}person[2]
/Q{}people[1]/Q{}person[2]/Q{}july[1]
/Q{}people[1]/Q{}person[2]/Q{}july[1]/Q{}Fridays[1]
/Q{}people[1]/Q{}person[3]
/Q{}people[1]/Q{}person[3]/Q{}july[1]
/Q{}people[1]/Q{}person[3]/Q{}july[1]/Q{}Fridays[1]
/Q{}people[1]/Q{}person[3]/Q{}july[1]/Q{}Fridays[1]/Q{}afternoons[1]

I guess I would prefer something that only shows the longest path for each person? I'm not crazy about the Q{}s, but that's a much lower priority.

/Q{}people[1]/Q{}person[1]/Q{}july[1]
/Q{}people[1]/Q{}person[2]/Q{}july[1]/Q{}Fridays[1]
/Q{}people[1]/Q{}person[3]/Q{}july[1]/Q{}Fridays[1]/Q{}afternoons[1]

Solution

  • I guess from your comment that your parser chops white-space so you want //*[not(*) and . = 'busy']!path(), to make sure you just select leaf elements.