0

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.

Cornel Raiu
  • 2,758
  • 3
  • 22
  • 31

2 Answers2

1

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;
odan
  • 4,757
  • 5
  • 20
  • 49
  • Thanks for the answer. The question I really need an answer to is: can this be achieved with `simplexml_load_string()` ? I already managed to parse it and use the details using XML Parser. Your solution works but it does not answer my question. – Cornel Raiu Jul 27 '19 at 21:12
  • that does return as "Valid XML". And that might be exactly because of the `NewDataSet` nodes children of `diffgr:diffgram`. So, XML is valid. Is it possible to parse it using `simplexml_load_string()`? The `var_dump`ed response for the test XML is: `object(SimpleXMLElement)[917]` when doing: `var_dump simplexml_load_string( $xml );` – Cornel Raiu Jul 27 '19 at 21:52
  • I will try this now: https://stackoverflow.com/questions/11315526/parsing-soap-response – Cornel Raiu Jul 27 '19 at 21:57
  • 1
    Good luck. simplexml_* is a little bit "limited" if you have very complex xml files. I would recommend using `DOMDocument`, because of the better namespace support. – odan Jul 27 '19 at 22:00
  • I managed to do it using that other question. Thanks for the help anyway! I am stuck to this library because of legacy code. It will be rewritten some time soon but the need to do this is right now. – Cornel Raiu Jul 27 '19 at 22:01
0

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!

Cornel Raiu
  • 2,758
  • 3
  • 22
  • 31