Cornel Raiu
Cornel Raiu

Reputation: 3005

parse XML with simplexml_load_string()

I have the following xml DataSet which comes from an API I have to use:

<?xml version="1.0" encoding="utf-8"?>
<DataSet xmlns="http://examplesite.com/WebRes">
  <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="BuildingInfo">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="ID_Building" type="xs:int" minOccurs="0" />
                <xs:element name="Name" type="xs:string" minOccurs="0" />
                <xs:element name="Description" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
    <NewDataSet xmlns="">
      <BuildingInfo diffgr:id="BuildingInfo1" msdata:rowOrder="0">
        <ID_Building>333</ID_Building>
        <Name>Example Building Name</Name>
        <Description />
      </BuildingInfo>
    </NewDataSet>
    <NewDataSet xmlns="">
      <BuildingInfo diffgr:id="BuildingInfo1" msdata:rowOrder="0">
        <ID_Building>334</ID_Building>
        <Name>Example Building Name2</Name>
        <Description />
      </BuildingInfo>
    </NewDataSet>
  </diffgr:diffgram>
</DataSet>

The problem with this one is that if I do the following:

<?php $result = simplexml_load_string( $xml, 'SimpleXMLElement', 0, 'xs' );

echo ($result ? 'Valid XML' : 'Parse Error'), PHP_EOL;
print_r( $result );

The result is:

Parse Error
SimpleXMLElement Object
(
)

As a fallback solution I used:

$p = xml_parser_create();
xml_parse_into_struct( $p, $xml, $result, $index );
xml_parser_free( $p );

Which is working just fine.

The other problem is that from the same API I also have responses like this:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfRoomTypeBuildingsDetails xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://examplesite.com/WebRes">
  <RoomTypeBuildingsDetails>
    <ID_RoomType>123</ID_RoomType>
    <RoomTypeName>Post Name</RoomTypeName>
    <RoomTypeDescription>This is the description</RoomTypeDescription>
    <GuestMax>2</GuestMax>
  </RoomTypeBuildingsDetails>
</ArrayOfRoomTypeBuildingsDetails>

Which work perfectly with the simplexml_load_string() function. That means I am using XML Parser for some of the responses and the simplexml_load_string() for the others which is not very easy to maintain.

The question here is: is there any way to parse both of the response types using simplexml_load_string()? or should I just switch to the XML Parser or DOMDocument or other similar library?

NOTE: from the first XML snippet, I am only interested in pulling the contents from the NewDataSet node.

Let me know if you need any more details. Any help is appreciated.

Upvotes: 0

Views: 323

Answers (2)

Cornel Raiu
Cornel Raiu

Reputation: 3005

The solution was to not use simplexml_load_string() but to parse it by creating a new SimpleXMLElement. It is still not using simplexml_load_string() but it allows me to use SimpleXMLElement to handle it.

My Test XML

<?xml version="1.0" encoding="utf-8"?>
<DataSet xmlns="http://examplesite.com/WebRes">
  <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="BuildingInfo">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="ID_Building" type="xs:int" minOccurs="0" />
                <xs:element name="Name" type="xs:string" minOccurs="0" />
                <xs:element name="Description" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
    <NewDataSet xmlns="">
      <BuildingInfo diffgr:id="BuildingInfo1" msdata:rowOrder="0">
        <ID_Building>333</ID_Building>
        <Name>Example Building Name</Name>
        <Description />
      </BuildingInfo>
    </NewDataSet>
    <NewDataSet xmlns="">
      <BuildingInfo diffgr:id="BuildingInfo1" msdata:rowOrder="0">
        <ID_Building>334</ID_Building>
        <Name>Example Building Name2</Name>
        <Description />
      </BuildingInfo>
    </NewDataSet>
  </diffgr:diffgram>
</DataSet>

My PHP Code

$sxe = new SimpleXMLElement($quote_response);
$sxe->registerXPathNamespace('d', 'urn:schemas-microsoft-com:xml-diffgram-v1');
$result = $sxe->xpath("//NewDataSet");

echo "<pre>";
foreach ($result[0] as $title) {
    print_r($title);
}
echo "</pre>";

The Result

SimpleXMLElement Object
(
    [ID_Building] => 333
    [Name] => Example Building Name
    [Description] => SimpleXMLElement Object
        (
        )

)

Thanks for the help!

Upvotes: 0

odan
odan

Reputation: 4952

Be careful checking for parse errors. An empty SimpleXMLElement may resolve to false, and if your XML contains no text or only contains namespaced elements your error check may be wrong. Always use === false when checking for parse errors.

Use this instead:

echo ($result !== false ? 'Valid XML' : 'Parse Error'), PHP_EOL;

Upvotes: 1

Related Questions