How to parse a SOAP XML response with Namespaces u

2019-08-09 14:40发布

问题:

I'm using CURL to send a SOAP request to Mondrian. This is the PHP code where CURL is being used:

$poststring =
    '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-        ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <SOAP-ENV:Header />
    <SOAP-ENV:Body>
    <Execute xmlns="urn:schemas-microsoft-com:xml-analysis">
    <Command>
    <Statement>
    select {[Measures].[Unit Sales]} on columns from Sales
    </Statement>
    </Command>
    <Properties>
    <PropertyList>
    <Catalog>FoodMart</Catalog>
    <DataSourceInfo>Provider=Mondrian;DataSource=MondrianFoodMart;</DataSourceInfo>
    <Format>Multidimensional</Format>
    <AxisFormat>TupleFormat</AxisFormat>
    </PropertyList>
    </Properties>
    </Execute>
    </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://localhost:8080/mondrian/xmla');
curl_setopt($ch, CURLOPT_POSTFIELDS, $poststring);
curl_setopt_array($ch, $this->_curlOptions);        
$_rawResult = curl_exec($ch);

curl_close($ch);

The received SOAP response I get from Mondrian is:

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP- ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" >
<SOAP-ENV:Header>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cxmla:ExecuteResponse xmlns:cxmla="urn:schemas-microsoft-com:xml-analysis">
<cxmla:return>
<root xmlns="urn:schemas-microsoft-com:xml-analysis:mddataset"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:EX="urn:schemas-microsoft-com:xml-analysis:exception">
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:schemas-microsoft-com:xml-analysis:mddataset" xmlns="urn:schemas-microsoft-com:xml-analysis:mddataset" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sql="urn:schemas-microsoft-com:xml-sql" elementFormDefault="qualified">
<xsd:complexType name="MemberType">
<xsd:sequence>
<xsd:element name="UName" type="xsd:string"/>
<xsd:element name="Caption" type="xsd:string"/>
<xsd:element name="LName" type="xsd:string"/>
<xsd:element name="LNum" type="xsd:unsignedInt"/>
<xsd:element name="DisplayInfo" type="xsd:unsignedInt"/>
        <xsd:sequence maxOccurs="unbounded" minOccurs="0">
          <xsd:any processContents="lax" maxOccurs="unbounded"/>
        </xsd:sequence>
      </xsd:sequence>
      <xsd:attribute name="Hierarchy" type="xsd:string"/>
    </xsd:complexType>
    <xsd:complexType name="PropType">
      <xsd:attribute name="name" type="xsd:string"/>
    </xsd:complexType>
    <xsd:complexType name="TupleType">
      <xsd:sequence maxOccurs="unbounded">
        <xsd:element name="Member" type="MemberType"/>
      </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="MembersType">
      <xsd:sequence maxOccurs="unbounded">
        <xsd:element name="Member" type="MemberType"/>
      </xsd:sequence>
      <xsd:attribute name="Hierarchy" type="xsd:string"/>
    </xsd:complexType>
    <xsd:complexType name="TuplesType">
      <xsd:sequence maxOccurs="unbounded">
        <xsd:element name="Tuple" type="TupleType"/>
      </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="CrossProductType">
      <xsd:sequence>
        <xsd:choice minOccurs="0" maxOccurs="unbounded">
          <xsd:element name="Members" type="MembersType"/>
          <xsd:element name="Tuples" type="TuplesType"/>
        </xsd:choice>
      </xsd:sequence>
      <xsd:attribute name="Size" type="xsd:unsignedInt"/>
    </xsd:complexType>
    <xsd:complexType name="OlapInfo">
      <xsd:sequence>
        <xsd:element name="CubeInfo">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="Cube" maxOccurs="unbounded">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="CubeName" type="xsd:string"/>
                  </xsd:sequence>
                </xsd:complexType>
              </xsd:element>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
        <xsd:element name="AxesInfo">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="AxisInfo" maxOccurs="unbounded">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="HierarchyInfo" minOccurs="0" maxOccurs="unbounded">
                      <xsd:complexType>
                        <xsd:sequence>
                          <xsd:sequence maxOccurs="unbounded">
                            <xsd:element name="UName" type="PropType"/>
                            <xsd:element name="Caption" type="PropType"/>
                            <xsd:element name="LName" type="PropType"/>
                            <xsd:element name="LNum" type="PropType"/>
                            <xsd:element name="DisplayInfo" type="PropType" minOccurs="0" maxOccurs="unbounded"/>
                          </xsd:sequence>
                          <xsd:sequence>
                            <xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
                          </xsd:sequence>
                        </xsd:sequence>
                        <xsd:attribute name="name" type="xsd:string" use="required"/>
                      </xsd:complexType>
                    </xsd:element>
                  </xsd:sequence>
                  <xsd:attribute name="name" type="xsd:string"/>
                </xsd:complexType>
              </xsd:element>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
        <xsd:element name="CellInfo">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:sequence minOccurs="0" maxOccurs="unbounded">
                <xsd:choice>
                  <xsd:element name="Value" type="PropType"/>
                  <xsd:element name="FmtValue" type="PropType"/>
                  <xsd:element name="BackColor" type="PropType"/>
                  <xsd:element name="ForeColor" type="PropType"/>
                  <xsd:element name="FontName" type="PropType"/>
                  <xsd:element name="FontSize" type="PropType"/>
                  <xsd:element name="FontFlags" type="PropType"/>
                  <xsd:element name="FormatString" type="PropType"/>
                  <xsd:element name="NonEmptyBehavior" type="PropType"/>
                  <xsd:element name="SolveOrder" type="PropType"/>
                  <xsd:element name="Updateable" type="PropType"/>
                  <xsd:element name="Visible" type="PropType"/>
                  <xsd:element name="Expression" type="PropType"/>
                </xsd:choice>
              </xsd:sequence>
              <xsd:sequence maxOccurs="unbounded" minOccurs="0">
                <xsd:any processContents="lax" maxOccurs="unbounded"/>
              </xsd:sequence>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="Axes">
      <xsd:sequence maxOccurs="unbounded">
        <xsd:element name="Axis">
          <xsd:complexType>
            <xsd:choice minOccurs="0" maxOccurs="unbounded">
              <xsd:element name="CrossProduct" type="CrossProductType"/>
              <xsd:element name="Tuples" type="TuplesType"/>
              <xsd:element name="Members" type="MembersType"/>
            </xsd:choice>
            <xsd:attribute name="name" type="xsd:string"/>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="CellData">
      <xsd:sequence>
        <xsd:element name="Cell" minOccurs="0" maxOccurs="unbounded">
          <xsd:complexType>
            <xsd:sequence maxOccurs="unbounded">
              <xsd:choice>
                <xsd:element name="Value"/>
                <xsd:element name="FmtValue" type="xsd:string"/>
                <xsd:element name="BackColor" type="xsd:unsignedInt"/>
                <xsd:element name="ForeColor" type="xsd:unsignedInt"/>
                <xsd:element name="FontName" type="xsd:string"/>
                <xsd:element name="FontSize" type="xsd:unsignedShort"/>
                <xsd:element name="FontFlags" type="xsd:unsignedInt"/>
                <xsd:element name="FormatString" type="xsd:string"/>
                <xsd:element name="NonEmptyBehavior" type="xsd:unsignedShort"/>
                <xsd:element name="SolveOrder" type="xsd:unsignedInt"/>
                <xsd:element name="Updateable" type="xsd:unsignedInt"/>
                <xsd:element name="Visible" type="xsd:unsignedInt"/>
                <xsd:element name="Expression" type="xsd:string"/>
              </xsd:choice>
            </xsd:sequence>
            <xsd:attribute name="CellOrdinal" type="xsd:unsignedInt" use="required"/>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
    <xsd:element name="root">
      <xsd:complexType>
        <xsd:sequence maxOccurs="unbounded">
          <xsd:element name="OlapInfo" type="OlapInfo"/>
          <xsd:element name="Axes" type="Axes"/>
          <xsd:element name="CellData" type="CellData"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <OlapInfo>
    <CubeInfo>
      <Cube>
        <CubeName>Sales</CubeName>
      </Cube>
    </CubeInfo>
    <AxesInfo>
      <AxisInfo name="Axis0">
        <HierarchyInfo name="Measures">
          <UName name="[Measures].[MEMBER_UNIQUE_NAME]"/>
          <Caption name="[Measures].[MEMBER_CAPTION]"/>
          <LName name="[Measures].[LEVEL_UNIQUE_NAME]"/>
          <LNum name="[Measures].[LEVEL_NUMBER]"/>
          <DisplayInfo name="[Measures].[DISPLAY_INFO]"/>
        </HierarchyInfo>
      </AxisInfo>
    </AxesInfo>
    <CellInfo>
      <Value name="VALUE"/>
      <FmtValue name="FORMATTED_VALUE"/>
      <FormatString name="FORMAT_STRING"/>
    </CellInfo>
  </OlapInfo>
  <Axes>
    <Axis name="Axis0">
      <Tuples>
        <Tuple>
          <Member Hierarchy="Measures">
            <UName>[Measures].[Unit Sales]</UName>
            <Caption>Unit Sales</Caption>
            <LName>[Measures].[MeasuresLevel]</LName>
            <LNum>0</LNum>
            <DisplayInfo>0</DisplayInfo>
          </Member>
        </Tuple>
      </Tuples>
    </Axis>
  </Axes>
  <CellData>
    <Cell CellOrdinal="0">
      <Value xsi:type="xsd:double">266773</Value>
      <FmtValue>266,773</FmtValue>
      <FormatString>Standard</FormatString>
    </Cell>
  </CellData>
</root>
</cxmla:return>
</cxmla:ExecuteResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

My objective is to extract all the Cell elements that come inside the CellData element. Although this response comes with only one Cell, it is possible that further answers come with more than one. I was thinking of using XPath, but I may be missing some detail related to Namespace registering:

$xml = simplexml_load_string($_rawResponse);
$xml->registerXPathNamespace('xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$xml->registerXPathNamespace('cxmla', 'urn:schemas-microsoft-com:xml-analysis');
$_res = $xml->xpath('//CellData/Cell');
var_dump($_res);

The result of var_dump is:

array(0) {
}

instead of something like:

array(1) {
  [0]=>
  object(SimpleXMLElement)#2 (4) {
    ["@attributes"]=>
    array(1) {
      ["CellOrdinal"]=>
      string(1) "0"
    }
    ["Value"]=>
    string(4) "266773"
    ["FmtValue"]=>
    string(5) "266,773"
    ["FormatString"]=>
    string(8) "Standard"
  }
}

What am I doing wrong? Could you point me in the right direction ? Thank you in advance.

回答1:

This is a namespace issue.

The <root> element, which is the parent of the <CellData> element, has a default namespace definition xmlns="urn:schemas-microsoft-com:xml-analysis:mddataset" so <CellData> is in that namespace (like all its descendants also happen to be). Therefore you need to register this namespace and give it some prefix and then use that prefix in your XPath steps.

$xml->registerXPathNamespace('md', 'urn:schemas-microsoft-com:xml-analysis:mddataset');
$_res = $xml->xpath('//md:CellData/md:Cell');

XPath queries always search for an element that is not in any namespace if the given element name is not prefixed.



回答2:

Using DOMDocument you can get all values in xml. Try with DOMDocument Documentation Link: http://php.net/manual/en/class.domdocument.php