Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie
Hi there,
There is an issue with role permissions that is being worked on at the moment.
If you are having trouble with access or permissions on regional forums please post here to get access: https://www.boards.ie/discussion/2058365403/you-do-not-have-permission-for-that#latest

XML parsing in PHP with simpleXML

  • 20-01-2009 10:14pm
    #1
    Registered Users, Registered Users 2 Posts: 5,618 ✭✭✭


    I'm trying to parse some XML with the new PHP SimpleXML libraries, but am running into difficulties. The XML is almost a soap mesage, and looks something like this
    <?xml version="1.0" encoding="UTF-8"?>
    <scenario xmlns="scenario.xsd">
     <global>
       <filter tag="startdate">MONTH+WEEK</filter>
       <filter tag="enddate">MONTH+WEEK+WEEK</filter>
      <input>
        <replace type="code">ABCD</replace>
        <replace type="language">en</replace>
      </input>
    ...
     </global>
    ...
    </scenario>
    

    I want to take the values of the filter tags and map them with the tag attribute as key. And I want to take the replace values and map them with the type attribute as key.

    So...
    map1: {startdate->MONTH+WEEK, enddate->MONTH+WEEK+WEEK}
    map2: {code->ABCD, language->en}

    So, this should be relatively simple, the documentation would suggest:
    $parser = simplexml_load_file($xml);
    $filters = array();
    foreach($parser->global->filter as $filter_node){
        $key = $filter_node['tag'];
        $filters[$key] = $filter_node;
    }
    $replaces = array();
    foreach($parser->global->input->replace as $replace_node{
        $key = $replace_node['type'];
        $replaces[$key] = $replace_node;
    }
    

    The catch is, it doesn't work.
    In fact, the foreach-es never seem to enter the loop at all.

    Rendering $parser as xml works fine, but attempting to print any sub nodes just fails. There are no warnings saying that the parser has failed.

    Of course, I could just use an xpath, but I can't stand being mocked by a class called simple XML :rolleyes:


Comments

  • Registered Users, Registered Users 2 Posts: 68,317 ✭✭✭✭seamus


    I suspect there's something missing in the initialisation of the parser. I had a bit of trouble when I started using simplexml, but flying along now. I have the code in work, and if you've no response by tomorrow morning, I'll take a look.


  • Registered Users, Registered Users 2 Posts: 68,317 ✭✭✭✭seamus


    This isn't actually as simple as you're tearing your hair out about :)
    This caught me out when I first started using it too:

    When you take any node from the SimpleXML tree, it returns a SimpleXMLElement object. Then when you perform functions on this object, such as "echo $node", it casts the object to the relevant data type, in the case of echo, it casts to a string.

    In your above example, if you take the first foreach loop, each $filter_node is a SimpleXMLElement, as is each $filter_node

    So you're trying to use a SimpleXMLElement object as the key in an array, which obviously won't work. So you need to cast it to a string before it can be used as the key in an array, i.e.
    [php]$key = (string) $filter_node;[/php]
    If you wish, you can also cast $filter_node itself to a string before adding it as an element in the array. This would cut down on the amount of memory used by the array, but if $filter_node has further attributes or subnodes, you will lose them.


  • Registered Users, Registered Users 2 Posts: 5,618 ✭✭✭Civilian_Target


    OK, that's great advice for later on - but the problem is more fundamental: we're not even getting into the foreach loop at
    foreach($parser->global->filter as $filter_node)
    


  • Registered Users, Registered Users 2 Posts: 68,317 ✭✭✭✭seamus


    I tested this, and indeed you are getting into these loops. :)

    Stick in some debugging such as
    [php]
    foreach($parser->global->filter as $filter_node){
    $key = (string) $filter_node;

    echo "$key => ".((string) $filter_node)."<br>";

    $filters[$key] = $filter_node;
    }[/php]


  • Registered Users, Registered Users 2 Posts: 68,317 ✭✭✭✭seamus


    Oh, and I'm assuming that's a code snippet, but you're aware that you're missing a closing parenthesis on line 8?


  • Advertisement
  • Registered Users, Registered Users 2 Posts: 5,618 ✭✭✭Civilian_Target


    Yeah, the original code is sample I just composed for the original on the spot - don't worry, the IDE prevents syntax mistakes.

    And I have tried such debugging - thats how I know it never makes it into the foreach, a die statement in there won't kill the script. Yet when you do
    echo $parser.toXML()
    
    , it outputs the xml that was input, with the correct names.

    *scratches head*


  • Registered Users, Registered Users 2 Posts: 5,618 ✭✭✭Civilian_Target


    woah - just Java-fied my PHP there, I do of course mean $parser->asXML()


  • Registered Users, Registered Users 2 Posts: 5,618 ✭✭✭Civilian_Target


    Aha - got it.
    Really simple - just compared my xpath and my SimpleXML and realised... it is of course case sensitive, but my code is not.

    Always the simple bugs :rolleyes:

    Thanks for your help


Advertisement