Stephen Grant
Stephen Grant

Reputation: 36

PHP - SimpleXML - Having difficulty converting a SOAP payload to objects; elements are missing or wrong

I'm in the process of parsing an XML payload using SimpleXML. I'm using and XSL transformation to remove namespace info etc; resulting in just a clean xml packet (by the way I had originally used preg_replace to get the same thing; but for other reasons have moved to xslt as we're doing more work that way in the future.)

The process appears to work fine; except for certain elements. In the following output Street Name attribute is missing.

If I take the XML code and paste it into http://xmlgrid.net/ (or any other) the payload parses as expected. I'm really puzzled. Help?

array(10) {
  ["BuildingName"]=>
  object(SimpleXMLElement)#28 (0) {
  }
  ["FloorNo"]=>
  object(SimpleXMLElement)#30 (0) {
  }
  ["UnitNo"]=>
  object(SimpleXMLElement)#31 (0) {    
  }
  ["LotNo"]=>
  string(3) "128"
  ["StreetNo"]=>
  string(3) "167"
  ["Street"]=>                      //  Missing Street Type
  string(4) "PITT"                  //  Should be Street in here
  ["City"]=>
   string(7) "REDFERN"
  ["State"]=>
  object(SimpleXMLElement)#32 (1) {
    ["@attributes"]=>
    array(1) {
      ["Name"]=>
      string(3) "NSW"
   }
  }
  ["Postcode"]=>
  string(4) "2015"
  ["Country"]=>
  string(9) "Australia"
} 

I'm experiencing difficulty with a couple of the elements. Sample code is as follows:

// Get the XML Packet and the transform

            $data = file_get_contents("/mnt/tmp/test.xml");
    $tsf = file_get_contents("/mnt/tmp/tsf.xslt");
    // Load the XML data source
    $xml= simplexml_load_file('/mnt/tmp/test.xml');
    // Load the XML stylesheet
    $xsl = simplexml_load_file('/mnt/tmp/tsf.xslt');
    // create an xslt processor instance
    $proc = new XSLTProcessor;
    // import the xsl stylesheet into the xslt processor
    $proc->importStyleSheet($xsl);
    // Transform and output the xml data source
    $m =  $proc->transformToXML($xml);

    var_dump ($m);
    $z = new SimpleXMLElement($m);

    $f= (array)$z->Body->ValuationTransaction->Message->ValuationType->FullRegistered->RealEstate->Location->Address;

    var_dump ($f);

XSLT is as follows:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>    

 <!-- keep comments -->
 <xsl:template match="comment()">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*">
    <!-- remove element prefix -->
    <xsl:element name="{local-name()}">
      <!-- process attributes -->
      <xsl:for-each select="@*">
        <!-- remove attribute prefix -->
        <xsl:attribute name="{local-name()}">
          <xsl:value-of select="."/>
        </xsl:attribute>
      </xsl:for-each>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

XML Payload is as follows:

<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><l:ValuationTransaction xmlns:l="http://www.lixi.org.au/schema/cal1.3/ValuationTransaction" ProductionData="Yes"><l:RevisionNumber LIXIVersion="1.0" UserType="Lender" /><l:Identifier Description="VMS" Type="ThirdPartyAssigned" UniqueID="9528465" /><l:Date>2013-10-18</l:Date><l:Time>13:52:24</l:Time><l:Comment></l:Comment><l:Publisher><l:RelatedEntityRef RelatedID="vms01" /></l:Publisher><l:Message><l:Identifier Description="VMS" Type="ThirdPartyAssigned" UniqueID="9528465" /><l:MessageRelatesTo><l:Identifier Type="LenderAssigned" UniqueID="1234567892" /></l:MessageRelatesTo><l:MessageBody Type="Information"><l:Status Name="Assigned">
        <l:Date>2013-10-18</l:Date>
        <l:Time>10:34:00
    </l:Time>
     </l:Status></l:MessageBody><l:ValuationType>
     <l:Identifier Description="Customer Name" Type="LenderAssigned" UniqueID="Mister Smith" />
     <l:Identifier Description="Loan Reference" Type="LenderAssigned" UniqueID="A-4000" />
     <l:Identifier Description="Customer Number" Type="LenderAssigned" UniqueID="" />
     <l:Identifier Description="Business Unit" Type="LenderAssigned" UniqueID="8023" />
     <l:Identifier Description="Valuation ID" Type="BrokerAssigned" UniqueID="1ZJX12380Y" />
     <l:Identifier Description="Replacement Valuation ID" Type="ThirdPartyAssigned" UniqueID="" />
     <l:Identifier Description="Replacement Valuation Type" Type="ThirdPartyAssigned" UniqueID="" />
     <l:Identifier Description="Valuer Reference Number" Type="ValuerAssigned" UniqueID="80145553" />
     <l:FullRegistered OtherReasonDescription="Other" PropertyTypeDescription="Fully Detached House" ReasonFor="Other" ValSubType="Standard">
        <l:RealEstate Status="Established">
           <l:Identifier Type="BrokerAssigned" UniqueID="80HLKWII" />
           <l:Residential Type="FullyDetachedHouse" />
           <l:EstimatedValue Amount="1000000" EstimateBasis="CustomerEstimate">
              <l:Date>2013-10-17</l:Date>
           </l:EstimatedValue>
           <l:Location>
              <l:Address>
                 <l:BuildingName />
                 <l:FloorNo />
                 <l:UnitNo />
                 <l:LotNo>128</l:LotNo>
                 <l:StreetNo>167</l:StreetNo>
                 <l:Street OtherTypeDescription="" Type="Street">PITT</l:Street>
                 <l:City>REDFERN</l:City>
                 <l:State Name="NSW" />
                 <l:Postcode>2015</l:Postcode>
                 <l:Country>Australia</l:Country>
              </l:Address>
           </l:Location>
        </l:RealEstate>
        <l:RequestDate>
           <l:Date>2013-10-17</l:Date>
        </l:RequestDate>
        <l:DetailedComment>
           <l:RelatedEntityRef RelatedID="80HLKWII" />
           <l:Comment />
        </l:DetailedComment>
        <l:FeeSegment>
           <l:Fee Amount="242.00" Class="Valuer">
              <l:Identifier UniqueID="CurrentFee" />
           </l:Fee>
           <l:Fee Amount="142.00" Class="Valuer">
              <l:Identifier UniqueID="InitialAllocationFee" />
           </l:Fee>
        </l:FeeSegment>
     </l:FullRegistered>
  </l:ValuationType></l:Message><l:RelatedPartySegment><l:RelatedParty RelPartyDescription="Sandstone VMS" RelPartyType="ServiceCentre"><l:Identifier Type="Sequential" UniqueID="vms01" /></l:RelatedParty><l:RelatedParty RelPartyDescription="Suncorp Metway" RelPartyType="Lender">
     <l:Identifier Type="Sequential" UniqueID="lender01" />
  </l:RelatedParty><l:RelatedParty RelPartyType="ValuationFirm">
     <l:Identifier Type="Sequential" UniqueID="valFirm01" />
     <l:Identifier Description="Reference ID" Type="ThirdPartyAssigned" UniqueID="2038" />
     <l:CompanyName BusinessName="TEST" />
     <l:Address>
        <l:NonStdAddress>PO Box 1444 </l:NonStdAddress>
        <l:City>Abbotsford</l:City>
        <l:State Name="NSW" />
        <l:Postcode>2216</l:Postcode>
        <l:Country>Australia</l:Country>
     </l:Address>
     <l:WorkPhone>
        <l:Phone>
           <l:FixedPhone>1300790000</l:FixedPhone>
        </l:Phone>
     </l:WorkPhone>
     <l:WorkPhone>
        <l:Phone>
           <l:Fax>1300 793 000</l:Fax>
        </l:Phone>
     </l:WorkPhone>
     <l:Email>[email protected]</l:Email>
  </l:RelatedParty><l:RelatedParty RelPartyType="Valuer">
     <l:Identifier Type="Sequential" UniqueID="valuer01" />
     <l:PersonName>
        <l:FirstName>Tasso</l:FirstName>
        <l:Surname>Balo</l:Surname>
     </l:PersonName>
     <l:Email>[email protected]</l:Email>
     <l:ProfessionalInfrastructure>
        <l:Accreditation AccreditationID="VAL010539" Type="Licence">
           <l:Identifier UniqueID="VAL010539" />
        </l:Accreditation>
     </l:ProfessionalInfrastructure>
  </l:RelatedParty><l:RelatedParty RelPartyType="AuthorisingValuer">
     <l:Identifier Type="Sequential" UniqueID="authValuer01" />
     <l:PersonName>
        <l:FirstName>Tasso</l:FirstName>
        <l:Surname>Balom</l:Surname>
     </l:PersonName>
     <l:Email>[email protected]</l:Email>
     <l:ProfessionalInfrastructure>
        <l:Accreditation AccreditationID="VAL010539" Type="Licence">
           <l:Identifier UniqueID="VAL010539" />
        </l:Accreditation>
     </l:ProfessionalInfrastructure>
  </l:RelatedParty><l:RelatedParty RelPartyDescription="Dean llings" RelPartyType="Instructor">
     <l:Identifier Description="Contact ID" UniqueID="Dean oll" />
     <l:PersonName>
        <l:FirstName>Dean</l:FirstName>
        <l:Surname>llings</l:Surname>
     </l:PersonName>
     <l:WorkPhone>
        <l:Phone>
           <l:FixedPhone>0355839</l:FixedPhone>
        </l:Phone>
     </l:WorkPhone>
     <l:Email>[email protected]</l:Email>
  </l:RelatedParty><l:RelatedParty RelPartyType="Vendor">
     <l:Identifier UniqueID="MJVR4IBY" />
     <l:PersonName IsPreferredContact="MostPreferred">
        <l:FirstName>Angelo</l:FirstName>
        <l:Surname>Gou</l:Surname>
     </l:PersonName>
     <l:HomePhone>
        <l:Phone>
           <l:FixedPhone>082909</l:FixedPhone>
        </l:Phone>
     </l:HomePhone>
     <l:HomePhone PreferredContactMethod="Yes">
        <l:Phone>
           <l:Mobile>082909</l:Mobile>
        </l:Phone>
     </l:HomePhone>
  </l:RelatedParty></l:RelatedPartySegment></l:ValuationTransaction></soapenv:Body></soapenv:Envelope>

Upvotes: 0

Views: 502

Answers (1)

IMSoP
IMSoP

Reputation: 97898

This may not be the answer you were looking for, but if you were only stripping namespaces because you didn't know how to use them with SimpleXML, check out the ->children and ->attributes methods.

Additionally, as the manual repeatedly states, var_dump etc will not give a full picture of a SimpleXML element, because it is a dynamic API, not a "normal" PHP object. Nor will you gain much by casting to (array). (In particular, an element with a string content and attributes, like Street in your example, only shows its text content.)

The things you need to know here are:

  • Namespaces can be referenced by their prefix, which might be different from document to document, or their URI, which won't.
  • Selecting a namespace with ->children() makes all subsequent uses of -> refer to children within that namespace, until you switch again with another call to ->children() or ->attributes()
  • To "switch to" the default or undefined namespace, you can pass NULL to ->children() or ->attributes().
  • An attribute with no prefix is always considered to have no namespace, even if the document declares a default namespace for elements with no prefix. This is an oddity of the XML Namespace spec, not of SimpleXML.

Here is an example (with a live demo here) of how to put this all together to echo the Type attribute of the Street element:

// Define constants to refer to namespaces without relying on a particular prefix
define('NS_SOAP', 'http://schemas.xmlsoap.org/soap/envelope/');
define('NS_VALUATION', 'http://www.lixi.org.au/schema/cal1.3/ValuationTransaction');

echo $xml
    // Body element is in the SOAP namespace
    ->children(NS_SOAP)->Body
    // Switch to the inner namespace
    ->children(NS_VALUATION)
    // Traverse to the element we want
    ->ValuationTransaction
    ->Message->ValuationType->FullRegistered->RealEstate->Location->Address
    ->Street
    // The attribute has no prefix, and is therefore not in any namespace, so we need to switch to the NULL namespace
    ->attributes(NULL)->Type;

Upvotes: 1

Related Questions