Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XPath Select node from current node value when the two attribute names are the same

Tags:

xml

xslt

xpath

Can anyone help me with this little issue I am having.

The XML

<MPN>
    <MTR MSN="AB123456"/>
    <MTR MSN="AB654321"/>
    <MTR MSN="AB654322"/>
    <MTR MSN="AB654323”/>
    <MTR MSN="AB654324"/>
    <JOB JobId="136">
        <JMR MSN="AB123456">
            <JRA DateActionRequiredBy="20090701120012" />
        </JMR>
        <JMR MSN="AB654321">
            <JRA DateActionRequiredBy="20090701100010" />
        </JMR>
    </JOB>
</MPN>

I would like to retrieve the DateActionRequiredBy from the JRA element, when the parser is sitting at the MTR Element, only one should be returned.

I have tried.

../JOB/JMR[@MSN = @MSN]/JRA/@DateActionRequiredBy

which returns {Dimension:[2]} NodeSet, this matches everything due to the @MSN attribute effectively matching itself not the parent.

../JOB/JMR[@MSN = ./@MSN]/JRA/@DateActionRequiredBy

which returns {Dimension:[2]} NodeSet

I have found a solution but it will require a variable inside every xsl:attribute which doesn't seem right to me.

<xsl:variable name="storeMSN" select="@MSN"/>
../JOB/JMR[@MSN = $storeMSN]/JRA/@DateActionRequiredBy

which returns 20090701120012 Attribute

This is what i am after, but there must be an easier way to achieve this other than a variable for every attribute.

Thanks in advance.

like image 743
Nanook Avatar asked Feb 27 '23 12:02

Nanook


1 Answers

<MPN>
    <MTR MSN="AB123456"/>
    <MTR MSN="AB654321"/><!-- current node (i.e. context node) -->
    <MTR MSN="AB654322"/>
    <MTR MSN="AB654323”/>
    <MTR MSN="AB654324"/>
    <JOB JobId="136">
        <JMR MSN="AB123456">
            <JRA DateActionRequiredBy="20090701120012" />
        </JMR>
        <JMR MSN="AB654321">
            <JRA DateActionRequiredBy="20090701100010" /><!-- desired node -->
        </JMR>
    </JOB>
</MPN>

then you would need to use this XPath:

../JOB/JMR[@MSN = current()/@MSN]/JRA/@DateActionRequiredBy

Note that this will work in XSLT only, since current() is an XSLT function.

You could ease the process by adding an XSL key:

<xsl:key name="kJMR" match="JMR" use="@MSN" />

and in XPath:

key('kJMR', @MSN)/JRA/@DateActionRequiredBy

Explanation why your tries don't work as expected. Both

  • ../JOB/JMR[@MSN = @MSN]/JRA/@DateActionRequiredBy
  • ../JOB/JMR[@MSN = ./@MSN]/JRA/@DateActionRequiredBy

compare @MSN with itself - an operation that can never fail. This way you always get all possible nodes.

Within a predicate, the XPath context always is the node that you apply the predicate to. The current() function is there to provide you with the XSLT context.

like image 131
Tomalak Avatar answered Apr 09 '23 21:04

Tomalak