Search code examples
phpparentdomdocumentxpathquery

PHP 7 DomDocument xpath query parent parameter


I'm trying to use eBaysvc.xsd not only to validate an xml but to build the xml itself:
therefore, passing as $API

AddDispute

I want to retrieve something like this xml:

<?xml version="1.0" encoding="utf-8"?>
<AddDisputeRequest xmlns="urn:ebay:apis:eBLBaseComponents">
  <DisputeExplanation> Tokens </DisputeExplanation>
  <DisputeReason> Tokens </DisputeReason>
  <ItemID> string </ItemID>
  <TransactionID> string </TransactionID>
  <OrderLineItemID> string </OrderLineItemID>
  <Version> string </Version>
  <RequesterCredentials>
    <eBayAuthToken> string </eBayAuthToken>
  </RequesterCredentials>
  <WarningLevel> Tokens </WarningLevel>
</AddDisputeRequest>

I built a script using xpath->query that should filter elements according to multiple parameters and so far I got this:

$Nodes = $xpath->query('//xs:element[(xs:annotation/xs:appinfo/ebl:CallInfo/ebl:CallName/text()="'.$API.'" or xs:annotation/xs:appinfo/ebl:CallInfo/ebl:AllCalls) and (xs:annotation/xs:appinfo/ebl:CallInfo/ebl:RequiredInput/text()="Yes" or xs:annotation/xs:appinfo/ebl:CallInfo/ebl:RequiredInput/text()="Conditionally")]')

but I need to add a further parameter, that is related not to the element but to his Ancestor:

assuming element with name="ItemID" we need to add to the query something like
and element:parent:parent:parent:parent[@name="'.$API.'Type"]

since we have this definition:

<xs:complexType name="AddDisputeRequestType">
    <xs:annotation>
        <xs:documentation>
            Enables a buyer and seller in an order relationship to
            send messages to each other's My Messages Inboxes.
        </xs:documentation>
        <xs:appinfo>
            <RelatedCalls>
                AddMemberMessagesAAQToBidder, AddMemberMessageRTQ
            </RelatedCalls>
        </xs:appinfo>
    </xs:annotation>
    <xs:complexContent>
        <xs:extension base="ns:AbstractRequestType">
            <xs:sequence>
                <xs:element name="ItemID" type="ns:ItemIDType" minOccurs="0">
                    ...
                </xs:element>
            </xs:sequence>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

but have no idea how to achieve this: can somebody suggest the solution

PS: is there an easier way to check for "Yes|Conditionally" in RequiredInput


Solution

  • To access ancestor of some node you could use expression like:

    //xs:element[ancestor::*[@name="AddDisputeRequestType"]]
    

    This expression employs xpath ancestor axis will select all (and any) elements that are ancestors of xs:element satisfying the predicate about name attribute. You might want to replace asterisk with some more specific element name.

    A little bit on axes stuff might be found here https://developer.mozilla.org/en-US/docs/Web/XPath/Axes and here https://www.w3.org/TR/xpath-10/#axes

    Please beware of some additional care might be needed in case multiple elements match the expression. Here is a short sample on that http://xsltransform.net/gVAjbTj

    Update:

    is there a like or contains operand

    I think you might use xpath function contains, like:

    //*[contains(name(), 'target')]

    what would select all elements that have "target" substring in their name.

    This construct pretty much can be used to check text content and attribute names, I've updated a fiddle a bit, you might wanna check it for samples and further fiddling: http://xsltransform.net/gVAjbTj/2 .

    And of course you're free to combine whatever you need to do any specific task, like "find all elements with this name that have some descendant with that name or any descendant with an attribute named whatever".

    Hope this helps )