PHP, XPath and SimpleXML - XPath does not really work or am I not getting something?

Discussion in 'PHP' started by Multiplexor, Jan 11, 2013.

  1. #1
    Here an example PHP and XML code:

    
    $XML = <<<XML
    <items>
        <item id="123">
            <name>Item 1</name>
        </item>
        <item id="456">
            <name>Item 2</name>
        </item>
        <item id="789">
            <name>Item 3</name>
        </item>
    </items>
    XML;
    
    
    $objSimpleXML = new SimpleXMLElement($XML);
    
    print_r($objSimpleXML->xpath('./item[1]'));
    print "- - - - - - -\n";
    print_r($objSimpleXML->xpath('./item[2][@id]'));
    print "- - - - - - -\n";
    print_r($objSimpleXML->xpath('./item[1]/name'));
    
    PHP:

    I know that I can access the id like this and it works fine:
    $objSimpleXML->items->item[0]['id']
    PHP:
    But since it is a dynamic application, the xpath is provided at runtime as string. Thus, I must take the xpath approach.

    The code above produces the following output:

    Array
    (
        [0] => SimpleXMLElement Object
            (
                [@attributes] => Array
                    (
                        [id] => 123
                    )
    
                [name] => Item 1
            )
    
    )
    - - - - - - -
    Array
    (
        [0] => SimpleXMLElement Object
            (
                [@attributes] => Array
                    (
                        [id] => 456
                    )
    
                [name] => Item 2
            )
    
    )
    - - - - - - -
    Array
    (
        [0] => SimpleXMLElement Object
            (
            )
    
    )
    PHP:
    I agree with the first output. But in the second output the whole element is returned instead of the attribute. Why?
    And the last listing is empty instead of name content? Why? What would be the correct xpath?

    My goal for the second and third output is:

    • 456 (just the value of the id-attribute of the second element)
    • Item 1 (just the name of the first element)
     
    Multiplexor, Jan 11, 2013 IP
  2. MockA

    MockA Greenhorn

    Messages:
    14
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    5
    #2
    // Just name
    print_r($objSimpleXML->xpath("//item[1]/name"));
    
    
    // Just id
    print_r($objSimpleXML->xpath("//item[2]/@id"));
    PHP:
    OUTPUT:
    Array ( [0] => SimpleXMLElement Object ( [0] => Item 1 ) )
    Array ( [0] => SimpleXMLElement Object ( [@attributes] => Array ( [id] => 456 ) ) )
    PHP:
     
    MockA, Jan 12, 2013 IP
  3. Multiplexor

    Multiplexor Greenhorn

    Messages:
    57
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    16
    #3
    Thanks a lot for the answer.
    According to documentation // returns ALL elements with this name, meaning that if there is an item element on a deeper level, its value is returned too, which is not desired. Isn't there a more reliable solution?

    One more question: how do you convert the result to string, especially the second one with the attribute id?
     
    Multiplexor, Jan 13, 2013 IP
  4. MockA

    MockA Greenhorn

    Messages:
    14
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    5
    #4
    Change it back to ./ and should work as desired. It's in the array so you can just pull it and echo as normal.

    // Just name
    $name = $objSimpleXML->xpath("./item[1]/name");
    echo $name[0];
    
    // Just id
    $id = $objSimpleXML->xpath("./item[2]/@id");
    echo $id[0];
    PHP:
    If you're really worried about it put (string) in front.
     
    MockA, Jan 13, 2013 IP
  5. Multiplexor

    Multiplexor Greenhorn

    Messages:
    57
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    16
    #5
    print_r($objSimpleXML->xpath('./item[1]/name'));
    PHP:
    returns an empty array, as reported in the original post.
    If you have another result, what might be the cause? Are there some PHP settings I have to consider?
     
    Multiplexor, Jan 13, 2013 IP
  6. MockA

    MockA Greenhorn

    Messages:
    14
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    5
    #6
    Doesn't return an empty array for me.

    <?php
    $XML = <<<XML
    <items>
        <item id="123">
            <name>Item 1</name>
        </item>
        <item id="456">
            <name>Item 2</name>
        </item>
        <item id="789">
            <name>Item 3</name>
        </item>
    </items>
    XML;
    
    $objSimpleXML = new SimpleXMLElement($XML);
    
    // Just name
    $name = $objSimpleXML->xpath("./item[1]/name");
    echo $name[0], PHP_EOL;
    
    // Just id
    $id = $objSimpleXML->xpath("./item[2]/@id");
    echo $id[0], PHP_EOL;
    ?>
    PHP:
    Also // should not return all item child nodes because you are asking for the first one with [1] so change it back to // and should work also. However for any kind of serious user-based application you'll want to use // and no array key and loop through them using a while statement.
     
    MockA, Jan 13, 2013 IP
    ryan_uk likes this.