MortiestMorty
MortiestMorty

Reputation: 635

Adding additional string to variable - PHP

Here's my problem. I want to create a function that takes an outside variable that contains an xpath and once the function runs I want to add to that same variable to create a counter.

So I have the outside variable:

 $node = $xmlDoc->xpath('//a:Order');

Then the function with a single argument that will take the outside variable ($node). Like so:

function loopXML($node) {
    i=1; //counter variable
}

Now I want to add a counter to $node so that it goes through all of the children of "Order". Outside of the function, I would use:

$child = $xmlDoc->xpath('//a:Order['.$i.']/*'); 

But inside of the function, I have no idea how to concat it. Does anyone have any idea how I could do this?

EDIT: Also, it should be noted that I created an arbitrary namespace already:

 foreach($xmlDoc->getDocNamespaces() as $strPrefix => $strNamespace) {
     if(strlen($strPrefix)==0) {
         $strPrefix="a"; //Assign an arbitrary namespace prefix.
     }
     $xmlDoc->registerXPathNamespace($strPrefix,$strNamespace);
 }

Upvotes: 0

Views: 91

Answers (2)

MortiestMorty
MortiestMorty

Reputation: 635

So I figured it out with a lot of Googling and the help of ThW. So to all that helped, thank you. Here's how I got it to work:

 $orderPNode = '//a:Order'; 
 $amazonRawXML = 'AmazonRaw.xml';
 $amazonRawCSV = 'AmazonRaw.csv';


function loopXML($xmlDoc, $node, $writeCsv) {
$i = 1;
$xmlDocs = simplexml_load_file($xmlDoc);
$result = [];

foreach($xmlDocs->getDocNamespaces() as $strPrefix => $strNamespace) {
    if(strlen($strPrefix)==0) {
        $strPrefix="a"; //Assign an arbitrary namespace prefix.
    }
$xmlDocs->registerXPathNamespace($strPrefix,$strNamespace);
}

file_put_contents($writeCsv, ""); // Clear contents of csv file after each go

$nodeP = $xmlDocs->xpath($node); 

foreach ($nodeP as $n) {
    $nodeC = $xmlDocs->xpath($node.'['.$i.']/*');
    if($nodeC) {
        foreach ($nodeC as $value) {
            $values[] = $value;
        }
    $write = fopen($writeCsv, 'a'); 
    fputcsv($write, $values);
    fclose($write);

    $values = [];
    $i++;
    } else {
        $result[] = $n;
        $i++;
    }

}
return $result;
}
loopXML($amazonRawXML, $orderPNode, $amazonRawCSV);

Upvotes: 0

ThW
ThW

Reputation: 19482

SimpleXMLElement::xpath() uses the node associated with the SimpleXML element as the context so you can do something like:

foreach ($xmlDoc->xpath('//a:Order') as $order) {
  foreach ($order->xpath('*') as $field) {
    ...
  }
} 

But SimpleXMLElement::children() is a list of the element child nodes so it returns the same as the Xpath expression * or to be more exact '*[namespace-uri == ""]'. The first argument is the namespace of the children you would like to fetch.

foreach ($xmlDoc->xpath('//a:Order') as $order) {
  foreach ($order->children() as $field) {
    ...
  }
}

This can be easily refactored into a function.

function getRecord(SimpleXMLelement $order, $namespace) {
  $result = [];
  foreach ($order->children($namespace) as $field) {
    $result[$field->getName()] = (string)$field;
  }
  return $result;
}

You should always depend on the actual namespace, never on the prefix. Prefixes can change and are optional.

Put all together:

$xml = <<<'XML'
<a:orders xmlns:a="urn:a">
  <a:order>
    <a:foo>bar</a:foo>
    <a:answer>42</a:answer>
  </a:order>
</a:orders>
XML;

$namespace = 'urn:a';

$orders = new SimpleXMLElement($xml);
$orders->registerXpathNamespace('a', $namespace);

function getRecord(SimpleXMLelement $order, $namespace = NULL) {
  $result = [];
  foreach ($order->children($namespace) as $field) {
    $result[$field->getName()] = (string)$field;
  }
  return $result;
} 

foreach ($orders->xpath('//a:order') as $order) {
  var_dump(getRecord($order, $namespace));
}

Output:

array(2) {
  ["foo"]=>
  string(3) "bar"
  ["answer"]=>
  string(2) "42"
}

Upvotes: 1

Related Questions