Remove XML child with same name - php

I have a large XML with the following:
<?xml version="1.0" encoding="UTF-8"?>
<valasz xmlns="" verzio="1.0">
<arak>
<ar>
<cikkid>439902</cikkid>
<cikkszam>DVDV-16Z10</cikkszam>
<listaar>1225,0000000</listaar>
<ar>1157,6200000</ar>
<akcios_ar>1157,6200000</akcios_ar>
<devizanem>HUF</devizanem>
</ar>
<ar>
..
<ar>1157,6200000</ar>
...
</ar>
</arak>
What i want is to remove arak->ar->ar child because its causing in the import it looks like duplicates, and slowing down the process.
I have tried the following:
$node = readfile($arlista[0]);
$nodes = simplexml_load_string($node);
$arnode = $nodes->xpath("/valasz/arak/ar/ar");
foreach ($arnode as &$ar){
$nodes->removeChild($ar);
}
echo $nodes;
And this only returns me the original xml, without removing the arak->ar->ar child nodes.
What am i doing wrong?

There is no such thing as ::removeChild() in SimpleXML.
What you want do do in your foreach loop is this:
foreach ($arnode as $ar){
unset($ar->{0});
}
Please note: The posted XML is not valid but I am sure that is just some kind of copy&paste flaw
Complete code:
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<valasz xmlns="" verzio="1.0">
<arak>
<ar>
<cikkid>439902</cikkid>
<cikkszam>DVDV-16Z10</cikkszam>
<listaar>1225,0000000</listaar>
<ar>1157,6200000</ar>
<akcios_ar>1157,6200000</akcios_ar>
<devizanem>HUF</devizanem>
</ar>
<ar>
<ar>1157,6200000</ar>
</ar>
</arak>
</valasz>';
$nodes = simplexml_load_string($xml);
$arnode = $nodes->xpath("/valasz/arak/ar/ar");
foreach ($arnode as $ar){
unset($ar->{0});
}
print_r($nodes);
Returns this
SimpleXMLElement Object
(
[#attributes] => Array
(
[verzio] => 1.0
)
[arak] => SimpleXMLElement Object
(
[ar] => Array
(
[0] => SimpleXMLElement Object
(
[cikkid] => 439902
[cikkszam] => DVDV-16Z10
[listaar] => 1225,0000000
[akcios_ar] => 1157,6200000
[devizanem] => HUF
)
[1] => SimpleXMLElement Object
(
)
)
)
)

Related

php simplexml_load_file and CDATA has data missing completely

I have the following xml file
<?xml version="1.0" encoding="UTF-8"?>
<data>
<item name="general.global.Event"><![CDATA[EVENT!]]></item>
<item name="general.global.CompanyName"><![CDATA[some name]]></item>
<item name="general.global.CompanyImprint"><![CDATA[Legal information]]></item>
</data>
and my code is as follows
$xml = simplexml_load_file("general.xml") or die("Error: Cannot create object");
print_r($xml);
and my output is missing the CDATA.. how?
SimpleXMLElement Object
(
[item] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => general.global.Event
)
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => general.global.CompanyName
)
)
[2] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => general.global.CompanyImprint
)
)
)
)
Text nodes are not exposed with print_r.
You can see the data there is you look at it explicitly:
print $xml->item[0];
The CDATA is being read, read this answer and you'll see that if you print_r($xml->asXML()); The parser recompiles the CDATA information just fine.
For some reason, PHP's var_dump and print_r don't have accurate representation of XML objects. Try this and you can still access the data:
foreach ($xml->item as $item) {
if ('general.global.CompanyImprint' === (string)$item['name']) {
var_dump((string)$item);
}
}
// prints
string(17) "Legal information"

SimpleXML: Selecting parent node based on content of child element

This should be am easy task, but I just didn't get it working:
In the below code snippet, I would like to select the <WebFilterCategory> node which has a <Name> child that has a value of "Categoryname2":
<?php
$xmlstring = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<Request>
<Login>
<UserName>admin</UserName>
<Password>admin</Password>
</Login>
<Set Operation="get">
<WebFilterCategory transactionid="">
<Name>Categoryname1</Name>
<Classification>Objectionable</Classification>
<DomainList>
<Domain>example1.com</Domain>
<Domain>example2.com</Domain>
</DomainList>
</WebFilterCategory>
<WebFilterCategory transactionid="">
<Name>Categoryname2</Name>
<Classification>Objectionable</Classification>
<DomainList>
<Domain>example1.org</Domain>
<Domain>example2.org</Domain>
</DomainList>
</WebFilterCategory>
</Set>
</Request>
XML;
$xml = simplexml_load_string( $xmlstring ) or die("Error: Cannot create object");
foreach ($xml->query('//WebFilterCategory/Name[contains(., "Categoryname2")]') as $category) {
print_r($xmlstring);
}
?>
Probably, there's a much leaner query to get the desired result, too.
The method you are looking for is not query but xpath
Then you could update the path to match the WebFilterCategory where the Name contains Categoryname2
//WebFilterCategory[Name[contains(., "Categoryname2")]]'
Updated code
$xml = simplexml_load_string( $xmlstring ) or die("Error: Cannot create object");
foreach ($xml->xpath('//WebFilterCategory[Name[contains(., "Categoryname2")]]') as $category) {
print_r($category);
}
Output
SimpleXMLElement Object
(
[#attributes] => Array
(
[transactionid] =>
)
[Name] => Categoryname2
[Classification] => Objectionable
[DomainList] => SimpleXMLElement Object
(
[Domain] => Array
(
[0] => example3.org
[1] => example2.org
)
)
)
See a Php demo

GPX file parse with PHP, get <extensions> element values

i have xml/gpx file:
<?xml version="1.0" encoding="utf-8"?>
<gpx xsi:schemaLocation="http://www.topografix.com/GPX/1/1">
<metadata>
....
</metadata>
<trk>
<trkseg>
<trkpt lat="50.04551333333333" lon="14.434101666666667">
<ele>282</ele>
<time>2014-06-30T20:56:03.92</time>
<extensions>
<gpxtpx:TrackPointExtension>
<gpxtpx:hr>100</gpxtpx:hr>
</gpxtpx:TrackPointExtension>
</extensions>
</trkpt>
...
</gpx>
Load:
$xml=simplexml_load_file($gpx_file);
parse witch
foreach($xml->trk->trkseg->trkpt as $point){}
Thats fine. But i cant get content of /extension//extension/
print_r($point) is
SimpleXMLElement Object
(
[#attributes] => Array
(
[lat] => 50.04527
[lon] => 14.433993333333333
)
[ele] => 280.5
[time] => 2014-06-30T20:57:21.71
[extensions] => SimpleXMLElement Object
(
)
)
and i cannot get SimpleXMLElement Object.
Print_r($point->extension is:
SimpleXMLElement Object
(
)
I try Converting a SimpleXML Object to an Array and other similiar way, but i have failed - output is empty array.
Any idea/way to get into string/array ?
Sample gpx is on www.vovcinec.net/gpx/e.gpx (~700kB)
You can't get them directly since they are in namespaces, you need to use getNamespaces() method first. Consider this example:
$xml = simplexml_load_file('e.gpx');
foreach($xml->trk->trkseg->trkpt as $trkpt) {
$namespaces = $trkpt->getNamespaces(true);
$gpxtpx = $trkpt->extensions->children($namespaces['gpxtpx']);
$hr = (string) $gpxtpx->TrackPointExtension->hr;
echo '<pre>';
print_r($hr);
echo '</pre>';
}
I hope you help following code
foreach($gpx->trk->trkseg->children() as $trkpts) {
echo (string)$trkpts->extensions->children('gpxtpx',true)->TrackPointExtension->hr;
}
no need to use getNamespaces() method

PHP - get values from xml

I have a some problem with get value from xml.
XML look like
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="http://crd.gov.pl/xml/schematy/UPO/2008/05/09/UPO.xsl"?>
<pos:Document xmlns:pos="SOMEURL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<pos:DescribeDoc/>
<pos:UPD>
<pos:IdDoc>procotol-UPD2198338</pos:IdDoc>
<pos:IdCases>221872</pos:IdCases>
<pos:additionalInfo TypeInfo="Source">Some string</pos:additionalInfo>
</pos:UPD>
...
I general try to get to pos:IdCases.
I try this code:
$domContent = new SimpleXMLElement(((string) $content), LIBXML_COMPACT);
$test = $domContent->xpath('/pos:Document/pos:UPD/*');
foreach($test as $node){
print_r($node)
}
I get a some object such as
SimpleXMLElement Object
(
[0] => procotol-UPD2198338
)
SimpleXMLElement Object
(
[0] => 221872
)
SimpleXMLElement Object
(
[#attributes] => Array
(
[TypeInfo] => Source
)
[0] => Some string
)
But I must get to pos:IdCases. I can't use index [1] because order can change.
My question is:
How can I get to value in node: pos:IdCases
I can't add id or another info to node because this xml was signed (XADES).
Can you give me some advice? Thanks for help
Simply change the XPath to match the <Pos:IdCases/> node:
$test = $domContent->xpath('/pos:Document/pos:UPD/pos:IdCases');

Why does SimpleXML change my array to the array's first element when I use it?

Here is my code:
$string = <<<XML
<?xml version='1.0'?>
<test>
<testing>
<lol>hello</lol>
<lol>there</lol>
</testing>
</test>
XML;
$xml = simplexml_load_string($string);
echo "All of the XML:\n";
print_r $xml;
echo "\n\nJust the 'lol' array:";
print_r $xml->testing->lol;
Output:
All of the XML:
SimpleXMLElement Object
(
[testing] => SimpleXMLElement Object
(
[lol] => Array
(
[0] => hello
[1] => there
)
)
)
Just the 'lol' array:
SimpleXMLElement Object
(
[0] => hello
)
Why does it output only the [0] instead of the whole array? I dont get it.
What #Yottatron suggested is true, but not at all the cases as this example shows :
if your XML would be like this:
<?xml version='1.0'?>
<testing>
<lol>
<lolelem>Lol1</lolelem>
<lolelem>Lol2</lolelem>
<notlol>NotLol1</lolelem>
<notlol>NotLol1</lolelem>
</lol>
</testing>
Simplexml's output would be:
SimpleXMLElement Object
(
[lol] => SimpleXMLElement Object
(
[lolelem] => Array
(
[0] => Lol1
[1] => Lol2
)
[notlol] => Array
(
[0] => NotLol1
[1] => NotLol1
)
)
)
and by writing
$xml->lol->lolelem
you'd expect your result to be
Array
(
[0] => Lol1
[1] => Lol2
)
but instead of it, you would get :
SimpleXMLElement Object
(
[0] => Lol1
)
and by
$xml->lol->children()
you would get:
SimpleXMLElement Object
(
[lolelem] => Array
(
[0] => Lol1
[1] => Lol2
)
[notlol] => Array
(
[0] => NotLol1
[1] => NotLol1
)
)
What you need to do if you want only the lolelem's:
$xml->xpath("//lol/lolelem")
That gives this result (not as expected shape but contains the right elements)
Array
(
[0] => SimpleXMLElement Object
(
[0] => Lol1
)
[1] => SimpleXMLElement Object
(
[0] => Lol2
)
)
It's because you have two lol elements. In order to access the second you need to do this:
$xml->testing->lol[1];
this will give you "there"
$xml->testing->lol[0];
Will give you "hello"
The children() method of the SimpleXMLElement will give you an object containing all the children of an element for example:
$xml->testing->children();
will give you an object containing all the children of the "testing" SimpleXMLElement.
If you need to iterate, you can use the following code:
foreach($xml->testing->children() as $ele)
{
var_dump($ele);
}
There is more information about SimpleXMLElement here:
http://www.php.net/manual/en/class.simplexmlelement.php
what you might want to do is using the Json encode/decode
$jsonArray = Json_decode(Json_encode($xml), true);
With the true argument you can call instead of using -> use [name]
so an example would be:
$xml = file("someXmlFile.xml");
$jsonArray = Json_decode(Json_encode($xml), true);
foreach(jsonArray['title'] as $title){
Do something with $titles
}
if you have more than 1 element it will typical put in an #attributes if the elements has attributes. This can be countered by using: $title = $title['#attributes']
Hope it could help.
Ah yes, I remember simple XML nearly doing my head in with this parsing arrays issue
Try the below code. It will give you an array of LOL elements, or, if you've just got a single LOL element, it will return that in an array as well.
The main advantage of that is you can do something like foreach ($lol as $element) and it will still work on a single (or on 0) LOL element.
<?php
$string = <<<XML
<?xml version='1.0'?>
<test>
<testing>
<lol>hello</lol>
<lol>there</lol>
</testing>
</test>
XML;
$xml = simplexml_load_string($string);
echo "<pre>";
echo "All of the XML:\n";
print_r($xml);
echo "\n\nJust the 'lol' array:\n";
$test_lols = $xml->testing->children();
$childcount = count($test_lols);
if ($childcount < 2) {
$lol = array($test_lols->lol);
}
else {
$lol = (array) $test_lols;
$lol = $lol['lol'];
}
print_r($lol);
?>
Ran into this issue...
Xpath can be a little slow, so you can achieve the same effect with a simple for loop.
for ($i = 0; $i < count($xml->testing->lol); $i++) {
print_r($xml->testing->lol[$i]);
}

Categories