Rob Bowman
Rob Bowman

Reputation: 8731

XPath to Get Value from Sibling with Namespace

I have the following xml doc:

<GetGeneralServiceRequestByReferenceValueResponse xmlns="http://www.caps-solutions.co.uk/webservices/connectors/731/servicerequest/messagetypes">
    <GeneralServiceRequest xmlns="http://www.caps-solutions.co.uk/schema/uniform/731/servicerequest/sr/srtypes">
        <ServiceRequestIdentification>
            <ServiceRequestTechnicalKey>PG7ECIJBKFX00</ServiceRequestTechnicalKey>
            <ReferenceValue>18/009969/S_SCBC</ReferenceValue>
            <AlternativeReferences>
                <AlternativeReference xmlns="http://www.caps-solutions.co.uk/schema/uniform/72b/common/uniformtypes">
                    <ReferenceValue>W44811182451</ReferenceValue>
                    <ReferenceType>UTRN</ReferenceType>
                </AlternativeReference>
                <AlternativeReference xmlns="http://www.caps-solutions.co.uk/schema/uniform/72b/common/uniformtypes">
                    <ReferenceValue>00482</ReferenceValue>
                    <ReferenceType>BAD</ReferenceType>
                </AlternativeReference>
            </AlternativeReferences>
            <SiteID>JB</SiteID>
        </ServiceRequestIdentification>
    </GeneralServiceRequest>
</GetGeneralServiceRequestByReferenceValueResponse>

I need to select the <ReferenceValue> that has a sibling <ReferenceType> of "UTRN"

The following xpath get's me the <ReferenceValue> of the last <Alternative> reference.

/*[local-name()='GetGeneralServiceRequestByReferenceValueResponse']/*[local-name()='GeneralServiceRequest']/*[local-name()='ServiceRequestIdentification']/*[local-name()='AlternativeReferences']/*[local-name()='AlternativeReference']/*[local-name()='ReferenceValue']

I've tried using [] for the parent AlternativeReference node then ReferenceValue='UTRN' but haven't been able to get the required output.

Upvotes: 1

Views: 147

Answers (3)

Dmitry Shyshkin
Dmitry Shyshkin

Reputation: 384

This should do:

"//AlternativeReference[1]/ReferenceValue"

Or if you know the sibling value:

"//ReferenceType[text()='UTRN']/parent::*/ReferenceValue"

Upvotes: 1

Tomalak
Tomalak

Reputation: 338316

Don't use local-name(). Declare the namespaces in your XSLT and use the prefixes.

For example, declare them like this (you can pick any prefixes you like, as long as the namespace URIs match):

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msg="http://www.caps-solutions.co.uk/webservices/connectors/731/servicerequest/messagetypes"
  xmlns:sr="http://www.caps-solutions.co.uk/schema/uniform/731/servicerequest/sr/srtypes"
  xmlns:uni="http://www.caps-solutions.co.uk/schema/uniform/72b/common/uniformtypes"
  exclude-result-prefixes="msg sr uni"
>

And use (wrapped for legibility, but XPath is not whitespace-sensitive, you can wrap it the same way in your XSLT):

/msg:GetGeneralServiceRequestByReferenceValueResponse
/sr:GeneralServiceRequest
/sr:ServiceRequestIdentification
/sr:AlternativeReferences
/uni:AlternativeReference[uni:ReferenceType = 'UTRN']
/uni:ReferenceValue

Here, /uni:AlternativeReference[uni:ReferenceType = 'UTRN'] only selects those <AlternativeReference> nodes who have a <ReferenceType> child of the wanted value.


Since there are many ways to look at an XML tree (and because I think that explicitly. naming. every. single. step. along. the. way. is overdoing it), something like this would also work:

//uni:ReferenceType[. = 'UTRN']/../uni:ReferenceValue

or

//uni:AlternativeReference[uni:ReferenceType = 'UTRN']/uni:ReferenceValue

Upvotes: 2

Mads Hansen
Mads Hansen

Reputation: 66783

You can add criteria to the <AlternativeReference> predicate to restrict the selection of <AlternativeReference> elements to those that have a <ReferenceType> element who's value is "UTRN":

/*[local-name()='GetGeneralServiceRequestByReferenceValueResponse']/
  *[local-name()='GeneralServiceRequest']/
    *[local-name()='ServiceRequestIdentification']/
      *[local-name()='AlternativeReferences']/
        *[local-name()='AlternativeReference' and *[local-name()='ReferenceType' and .='UTRN']]/
          *[local-name()='ReferenceValue'] 

Upvotes: 2

Related Questions