1

I've been trying to parse this xml document to loop the 'table' element for the last 2 hours, but it's not working ! I've tried this mainly as reference but it's not working simplexml_load_string returns blank array

here's my XML, how can I loop through the 'table' node ?

    <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetMovieListResult xmlns="http://vista.co.nz/services/WSVistaWebClient.DataTypes/1/"><Result>OK</Result><DatasetXML><NewDataSet>
      <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="Table">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="Cinema_strID" type="xs:string" minOccurs="0" />
                    <xs:element name="Movie_strID" type="xs:string" minOccurs="0" />
                    <xs:element name="Movie_strName" type="xs:string" minOccurs="0" />
                    <xs:element name="Movie_strRating" type="xs:string" minOccurs="0" />
                    <xs:element name="Movie_strName_2" type="xs:string" minOccurs="0" />
                    <xs:element name="Movie_strRating_2" type="xs:string" minOccurs="0" />
                    <xs:element name="Movie_HOFilmCode" type="xs:string" minOccurs="0" />
                    <xs:element name="Movie_intFCode" type="xs:int" minOccurs="0" />
                    <xs:element name="CinOperator_strCode" type="xs:int" minOccurs="0" />
                    <xs:element name="CinOperator_strName" type="xs:int" minOccurs="0" />
                    <xs:element name="Event_strCode" type="xs:string" minOccurs="0" />
                    <xs:element name="Event_strFilmsIndependent" type="xs:string" minOccurs="0" />
                    <xs:element name="MemberMovie" type="xs:string" minOccurs="0" />
                    <xs:element name="HOPK" type="xs:string" minOccurs="0" />
                    <xs:element name="Movie_intList_Pos" type="xs:int" minOccurs="0" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:choice>
          </xs:complexType>
        </xs:element>
      </xs:schema>
      <Table>
        <Cinema_strID>0</Cinema_strID>
        <Movie_strID>0010000845</Movie_strID>
        <Movie_strName>BATMAN Vs SUPERMAN</Movie_strName>
        <Movie_strRating>PG13</Movie_strRating>
        <Movie_strName_2 />
        <Movie_strRating_2 />
        <Movie_HOFilmCode />
        <Movie_intFCode>0</Movie_intFCode>
        <Event_strCode />
        <MemberMovie>N</MemberMovie>
        <HOPK />
        <Movie_intList_Pos>50</Movie_intList_Pos>
      </Table>
      <Table>
        <Cinema_strID>0</Cinema_strID>
        <Movie_strID>0010000846</Movie_strID>
        <Movie_strName>BATMAN Vs SUPERMAN VIP</Movie_strName>
        <Movie_strRating>PG13</Movie_strRating>
        <Movie_strName_2 />
        <Movie_strRating_2 />
        <Movie_HOFilmCode />
        <Movie_intFCode>0</Movie_intFCode>
        <Event_strCode />
        <MemberMovie>N</MemberMovie>
        <HOPK />
        <Movie_intList_Pos>50</Movie_intList_Pos>
      </Table>

    </NewDataSet></DatasetXML></GetMovieListResult></soap:Body></soap:Envelope>
1
  • last I tried was this, but it's like one of many attempts, I lost track and logic honestly : $parser = simplexml_load_string($xml); $parserEnv = $parser->children('soap', true); $movies = $parserEnv->Body ->GetMovieListResult->children(); Commented Mar 24, 2016 at 8:37

1 Answer 1

1

Probably you have some issue with NameSpaceURIs.

NamespaceURIs are characterized by tags with colon (<soap:Envelope>) and by NamespaceURI declaration, an attribute (usually of root element) with “xmlns:” prefix:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" .... >
<!--           └──┬─┘└┬─┘  └────────────────────────┬──────────────┘
                  │   └──────┐                      │
   NameSpace Declaration   NameSpace Prefix   NameSpaceURI      -->

The main NameSpaceURI, applied to tags without prefix, is characterized by attribute “xmlns”, without comma.

To search for NameSpaceURI elements, you can use ->children(), using as argument relative NameSpaceURI:

$children = $xml->children( 'http://schemas.xmlsoap.org/soap/envelope/' );

or, adding optional parameter is_prefix_, the NameSpaceURI prefix:

$children = $xml->children( 'soap', True );

In your case, before accessing <Table>, you have to select direct parent node:

$xml = simplexml_load_file( $filePath );

$body               = $xml->children( 'soap', True );
$GetMovieListResult = $body->children();
$NewDataSet         = $GetMovieListResult->children()->DatasetXML->NewDataSet;
#                                                      └───────────────────┬┘
#                                         Here we can use standard syntax ─┘

At this point, we can catch, e.g., all movie names:

$movieNames = array[];
foreach( $NewDataSet->Table as $table )
{
    $movieNames[] = (string) $table->Movie_strName;
}

Now $movieNames array you have:

Array
(
    [0] => BATMAN Vs SUPERMAN
    [1] => BATMAN Vs SUPERMAN VIP
)

By this method, you can retrieve any other node value.


Using XPath

A more comfortable method is to use XPath, a syntax that uses path expressions to navigate in XML documents. To using XPath in a Namespaced XML, first we have to register the Namespace(s) that we want to use in the pattern:

$xml->registerXPathNamespace( 'xmlns', 'http://vista.co.nz/services/WSVistaWebClient.DataTypes/1/' );

In this case, I have registered main NameSpaceURI1. Then we can search for the pattern:

$tables = '//xmlns:Table';

The double slash at beginning of pattern means: “Search for nodes matching following pattern no matter where they are”2. Now, we have a set of nodes that we can iterate through as precedent example:

foreach( $tables as $table )
{
    (...)


Notes:

  1. We can use any characters combination registering NameSpaces, not necessarily that one used in the document. I.e. if I register main NS in this way: $xml->registerXPathNamespace( 'x', 'http://vista.co.nz/services/WSVistaWebClient.DataTypes/1/' );, then I can construct XPath pattern in this way: //x:Table.

  2. To search the exact descending tree, we can use / instead of //. In this case, however, we have to register all NameSpaces that appear in the tree.

Sign up to request clarification or add additional context in comments.

2 Comments

ah great , thanks! that worked ! isn't there a way to dump the xml class like print_r works to actually see what's going on? it's hard/confusing to track what's happening blindly
@roynaufal In the example I have named variable with respective tag elements precisely to better understand! :( You can't print_r , but you can use ->asXML() to see what nodes are in each step ( echo $body->asXML() etc...). Also properly indenting your XML can help you to understand. In my answer I use pure SimpleXML syntax because you refer to a previous answer that use it, but now I have edited answer adding a chapter about XPath, that can be more simple, in your case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.