Как использовать XPath для XML с импортом? - PullRequest
1 голос
/ 24 октября 2019

Я пытаюсь разобрать файл WSDL для создания классов PHP. Хотя для этого существует множество инструментов, все они в настоящее время не в состоянии документировать доступные SOAPHeaders и SOAPFaults, которые существуют для запроса и / или ответа.

У меня достаточно понимания, чтобы построить это:https://github.com/rquadling/wsdl2php. Но затем я сталкиваюсь с сервисом, который не соответствует моим предыдущим знаниям.

Итак. Пример WSDL-файла (используется только как метод входа в систему и некоторые операции импорта).

<?xml version="1.0" encoding="UTF-8"?>
<definitions
        xmlns:tns="urn:platform_2012_2.webservices.netsuite.com"
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns="http://schemas.xmlsoap.org/wsdl/"
        xmlns:platformMsgs="urn:messages_2012_2.platform.webservices.netsuite.com"
        xmlns:platformFaults="urn:faults_2012_2.platform.webservices.netsuite.com"
        targetNamespace="urn:platform_2012_2.webservices.netsuite.com">
    <types>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
            <xsd:import namespace="urn:core_2012_2.platform.webservices.netsuite.com" schemaLocation="https://webservices.eu2.netsuite.com/xsd/platform/v2012_2_0/core.xsd"/>
            <xsd:import namespace="urn:faults_2012_2.platform.webservices.netsuite.com" schemaLocation="https://webservices.eu2.netsuite.com/xsd/platform/v2012_2_0/faults.xsd"/>
            <xsd:import namespace="urn:messages_2012_2.platform.webservices.netsuite.com" schemaLocation="https://webservices.eu2.netsuite.com/xsd/platform/v2012_2_0/messages.xsd"/>
            <xsd:import namespace="urn:common_2012_2.platform.webservices.netsuite.com" schemaLocation="https://webservices.eu2.netsuite.com/xsd/platform/v2012_2_0/common.xsd"/>
            <!-- snip -->
        </xsd:schema>
    </types>
    <message name="headers">
        <part name="applicationInfo" element="platformMsgs:applicationInfo"/>
        <part name="partnerInfo" element="platformMsgs:partnerInfo"/>
        <part name="documentInfo" element="platformMsgs:documentInfo"/>
        <part name="preferences" element="platformMsgs:preferences"/>
        <part name="searchPreferences" element="platformMsgs:searchPreferences"/>
        <part name="passport" element="platformMsgs:passport"/>
    </message>
    <message name="loginRequest">
        <part name="parameters" element="platformMsgs:login"/>
    </message>
    <message name="loginResponse">
        <part name="parameters" element="platformMsgs:loginResponse"/>
    </message>
    <!-- snip -->
    <portType name="NetSuitePortType">
        <operation name="login">
            <input name="loginRequest" message="tns:loginRequest"/>
            <output name="loginResponse" message="tns:loginResponse"/>
            <fault name="InsufficientPermissionFault" message="tns:InsufficientPermissionFault"/>
            <fault name="InvalidAccountFault" message="tns:InvalidAccountFault"/>
            <fault name="InvalidCredentialsFault" message="tns:InvalidCredentialsFault"/>
            <fault name="InvalidVersionFault" message="tns:InvalidVersionFault"/>
            <fault name="ExceededRequestLimitFault" message="tns:ExceededRequestLimitFault"/>
            <fault name="UnexpectedErrorFault" message="tns:UnexpectedErrorFault"/>
        </operation>
        <!-- snip -->
    </portType>
    <binding name="NetSuiteBinding" type="tns:NetSuitePortType">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="login">
            <soap:operation soapAction="login"/>
            <input name="loginRequest">
                <soap:header message="tns:headers" part="applicationInfo" use="literal"/>
                <soap:header message="tns:headers" part="partnerInfo" use="literal"/>
                <soap:body use="literal"/>
            </input>
            <output name="loginResponse">
                <soap:body use="literal"/>
            </output>
            <fault name="InsufficientPermissionFault">
                <soap:fault name="InsufficientPermissionFault" use="literal"/>
            </fault>
            <fault name="InvalidAccountFault">
                <soap:fault name="InvalidAccountFault" use="literal"/>
            </fault>
            <fault name="InvalidCredentialsFault">
                <soap:fault name="InvalidCredentialsFault" use="literal"/>
            </fault>
            <fault name="InvalidVersionFault">
                <soap:fault name="InvalidVersionFault" use="literal"/>
            </fault>
            <fault name="ExceededRequestLimitFault">
                <soap:fault name="ExceededRequestLimitFault" use="literal"/>
            </fault>
            <fault name="UnexpectedErrorFault">
                <soap:fault name="UnexpectedErrorFault" use="literal"/>
            </fault>
        </operation>
        <!-- snip -->
    </binding>
    <service name="NetSuiteService">
        <port name="NetSuitePort" binding="tns:NetSuiteBinding">
            <soap:address location="https://webservices.eu2.netsuite.com/services/NetSuitePort_2012_2"/>
        </port>
    </service>
</definitions>

Я использую XPath для извлечения заголовков (вход и выход) и ошибок ...

    $xPathMaster['Headers'] = [
        'headers_in' => [
            'Definitions/Binding/Operation[method]/Input/Header' => '//*[local-name()="definitions"]/*[local-name()="binding"]/*[local-name()="operation"][@name="'.$call.'"]/*[local-name()="input"]/*[local-name()="header"]/@part',
        ],
        'headers_out' => [
            'Definitions/Binding/Operation[method]/Output/Header' => '//*[local-name()="definitions"]/*[local-name()="binding"]/*[local-name()="operation"][@name="'.$call.'"]/*[local-name()="output"]/*[local-name()="header"]/@part',
        ],
        'faults' => [
            'Definitions/Binding/Operation[method]/fault' => '//*[local-name()="definitions"]/*[local-name()="binding"]/*[local-name()="operation"][@name="'.$call.'"]/*[local-name()="fault"]/@name',
        ],
    ];

($call - это имя вызываемого метода).

Так что мой инструмент знает, что заголовок applicationInfo связан с loginResponse.

ЧтоЯ не уверен, как это сделать, программно найти структуру для этого типа.

Вручную, я знаю, что она существует как сопоставленный тип в импорте пространства имен сообщений из https://webservices.eu2.netsuite.com/xsd/platform/v2012_2_0/messages.xsd ...

<!-- snip -->
<complexType name="ApplicationInfo">
  <sequence>
    <element name="applicationId" minOccurs="0" type="xsd:string"/>
  </sequence>
</complexType>
<element name="applicationInfo" type="platformMsgs:ApplicationInfo"/>

Я использую PHP-технологию SOAP, и она может дать мне список типов ($client->__getTypes(), но это показывает структуру как ...

struct ApplicationInfo {
 string applicationId;
}

(поэтому он должен выполнить импорт изнутри), но без упоминания applicationInfo.

Так что, пытаясь сделать это через PHP DOM, используя запросы XPath, и я теряюсь, как «расширить» импорт такфактический контент присутствует, а не ссылка.

Я вроде как потерян.

1 Ответ

0 голосов
/ 25 октября 2019

Я вообще не эксперт по PHP, но я думаю, что технология PHP SOAP делает это правильно. Список типов ( Определения типов XSD ) в этом XSD не должен включать applicationInfo, поскольку applicationInfo является объявлением элемента XSD . (Я предполагаю, что $ client - это ссылка на импортированную схему, кстати)

В качестве общего комментария вы также можете иметь в виду, что импортированный XSD может импортировать другие XSD, которые могут импортировать другие XSD. ..и т.д. Поэтому, если вам действительно нужно работать со всей структурой заголовка / ошибки, вам нужно будет пройти весь путь вниз по вложенному импорту.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...