I have the following XML code:
<administration>
<notes>
<note>
<id>12312312</id>
<name>Lorem Ipsum</name>
<reference>Target Value - 1</reference>
</note>
<note>
<id>12312365</id>
<name>Lorem Ipsum</name>
<references>
<code>Dolor it se met.</code>
<code>Target Value - 2</code>
</references>
</note>
<note>
<id>12375512</id>
<name>Target Value - 3</name>
<reference>S</reference>
</note>
</notes>
<accounting>
<ledgers>
<ledger>
<debits>
<debit>
<description>Target Value - 4</description>
<amount>5467.32</amount>
</debit>
<debit>
<description>My Debit</description>
<amount>5467.32</amount>
<tags>
<tag>Target Value - 5</tag>
</tags>
</debit>
</debits>
<credits>
<credit>
<title>Target Value - 6</title>
<amount>873.00</amount>
</credit>
<credit>
<description>Target Value - 7</description>
<amount>23454.12</amount>
</credit>
</credits>
</ledger>
</ledgers>
</accounting>
</administration>
I'm trying to get a PHP array which consists of only the values of the nodes which have a value containing this string: "Target Value". This has to be done on a recursive way, using an XML parser (I'm trying SimpleXML, but I'm new to that).
Up 'till now, I've been trying to use SimpleXmlIterator and foreach- and for-loops to achieve this, but I can't seem to check if a node value contains "Target Value".
Edit: reaching the target nodes by manually referring to them is not what I'm looking for, if I were, there would be no problem
Is there any way to achieve this?
EDIT:
Here is the code of my last try:
function sxiToArray($sxi)
{
$a = array();
for( $sxi->rewind(); $sxi->valid(); $sxi->next() )
{
if(!array_key_exists($sxi->key(), $a))
{
$a[$sxi->key()] = array();
}
if($sxi->hasChildren())
{
if (strpos((string)$sxi->current(), "Target Value"))
$a[$sxi->key()][] = sxiToArray($sxi->current());
}
else
{
if (strpos((string)$sxi->current(), "Target Value"))
$a[$sxi->key()][] = strval($sxi->current());
}
}
return $a;
}
$xmlArray = xml2array('../Document.xml');
print_r($xmlArray);
This gives the following result after running:
Array ( [notes] => Array ( ) [accounting] => Array ( ) )
It does not have to be done in an recursive way. You can use Xpath. Xpath uses location paths as part of an expression. The paths use different axes - one of them is descendant. It "ignores" the nesting. Xpath allows you to use conditions.
//*
//*[./text()]
//*[./text()[contains(., "Target Value")]]
Put together it is a fairly small piece of code:
$administration = new SimpleXMLElement($xml);
$nodes = $administration->xpath('//*[./text()[contains(., "Target Value")]]');
foreach ($nodes as $node) {
var_dump($node->getName(), (string)$node);
}
Output:
string(9) "reference"
string(16) "Target Value - 1"
string(4) "code"
string(16) "Target Value - 2"
string(4) "name"
string(16) "Target Value - 3"
string(11) "description"
string(16) "Target Value - 4"
string(3) "tag"
string(16) "Target Value - 5"
string(5) "title"
string(16) "Target Value - 6"
string(11) "description"
string(16) "Target Value - 7"
And with DOM it would not look much different:
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$nodes = $xpath->evaluate('//*[./text()[contains(., "Target Value")]]');
foreach ($nodes as $node) {
var_dump($node->localName, $node->textContent);
}