1

I have Xml file like

<response>
<tag1>
    <item>
        <id>106</id>
        <title>DG</title>
    </item>
    <item>
        <id>105</id>
        <title>AC</title>
    </item>
</tag1>
<tag2>
    <item>
        <id>1</id>
        <title>DjG</title>
    </item>
    <item>
        <id>15</id>
        <title>AoC</title>
    </item>
</tag2>
</response>

I trying this code to extract ID and Title

$dom = new DomDocument();
    $dom->load('xml.xml');
    $xpath = new DOMXPath($dom);

    foreach($xpath->evaluate('//response/*') as $node){
    $params =$xpath->evaluate('//response/' .$node->nodeName . '/item/*');
        foreach($params as $child) {
            echo $node->nodeName ." = " .$child->nodeName ." = " .$child->nodeValue ."\n<br>";
        }
    }

But I get result such

<br>tag1 = id = 106
<br>tag1 = title = DG
<br>tag1 = id = 105
<br>tag1 = title = AC
<br>tag2 = id = 1
<br>tag2 = title = DjG
<br>tag2 = id = 15
<br>tag2 = title = AoC

But i need to get like this


tag1 = 106 = DG
tag1 = 105 = AC
tag2 = 1 = DjG
tag2 = 15 = AoC

3 Answers 3

3

On the second foreach, just target that $node->nodeName, then on the inner foreach target each id an title.

foreach($xpath->evaluate('//response/*') as $node) {
    $tag = $node->nodeName;
    $params = $xpath->evaluate("//$tag/*");
    foreach($params as $child) {
        $id = $xpath->evaluate('string(./id)', $child);
        $title = $xpath->evaluate('string(./title)', $child);
        echo $tag ." = " .$id ." = " .$title ."\n<br>";
    }
}

Sample Output

Or the SimpleXML version:

$xml = simplexml_load_file('xml.xml');
foreach($xml as $tag =>$node) {
    foreach($node as $item => $child) {
        echo $tag ." = " .$child->id ." = " .$child->title ."\n<br>";
    }
}

Sample Output

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

4 Comments

@DmitrijHolkin just get the individual child, check my revision
@DmitrijHolkin i can't be sure which, maybe benchmark would yield accurate results, SimpleXML's lines are shorter thats for sure.
second variant is usable if "response" tag is root, but if not when how to use? foreach($xml->response ?
@DmitrijHolkin yes could be, if <response> is a direct child of the root node.
1

Use this code:

$dom = new DomDocument();
$dom->load('xml.xml');
$xpath = new DOMXPath($dom);
foreach($xpath->evaluate('//response/*') as $node){
    $params =$xpath->evaluate('//response/' .$node->nodeName . '/*');

     foreach($params as $child) 
    {
       echo $node->nodeName ." = " .$child->getElementsByTagName('id')->item(0)->textContent ." = " .$child->getElementsByTagName('title')->item(0)->textContent  ."\n<br>";
    }
}

1 Comment

Notice: Undefined property: DOMNodeList::$item
1

The second argument of DOMXpath::evaluate() is the context node. If you do not start the XPath expression with a slash, it will be relative to it. So inside a loop, you usually want to use the current node as the context for your expressions.

foreach ($xpath->evaluate('/absolute-expression') as $node) {
  var_dump(
     $xpath->evaluate('relative-expression', $node)
  );
}

XPath (unlike CSS selectors) can fetch properties of the elements along different axes. You can get the local name (without namespace prefix) of a parent node with:

local-name(parent::*)

Using this, you can solve the problem with a single loop iterating the item elements.

Example:

$dom = new DomDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);

foreach ($xpath->evaluate('//response/*/item') as $node) {
  echo 
    $xpath->evaluate('local-name(parent::*)', $node), ' = ',
    $xpath->evaluate('string(id)', $node), ' = ',
    $xpath->evaluate('string(title)', $node), "\n";
}

Output:

tag1 = 106 = DG
tag1 = 105 = AC
tag2 = 1 = DjG
tag2 = 15 = AoC

Only, If you need to call source for each first level node (tag1, tag2). You will need two loops. Like output the items grouped by the tag* element node.

$dom = new DomDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);

foreach ($xpath->evaluate('//response/*') as $node) {
  echo  
    $xpath->evaluate('local-name()', $node), 
    "\n--------\n";
  foreach ($xpath->evaluate('item', $node) as $item) {
    echo 
      $xpath->evaluate('string(id)', $item), ' = ',
      $xpath->evaluate('string(title)', $item), "\n";
  }
  echo "\n";
}

Output:

tag1
--------
106 = DG
105 = AC

tag2
--------
1 = DjG
15 = AoC

2 Comments

only trouble how to use put each local-name to separate php file as array $data= "\n'" .$xpath->evaluate('string(id)', $node) ."' => '" .$xpath->evaluate('string(title)', $node). "',"; _ file_put_contents("." .$path .$xpath->evaluate('local-name(parent::*)', $node) .'.php', '<?php $arr = array(' .$data .'\n);\n?>' ); not work wery well
This is not an request in your original question. I added an example to my answer.

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.