Edit an XML-structure with PHP - php

I am trying to convert an XML-file through a PHP-script. I have the following structure:
<?xml version="1.0"?>
<persons>
<person id="1">
<periods>3</periods>
<name id="John"/>
<times>
<time>
<day id="1"/>
<time>35:28</time >
<length>8000</length>
</time>
<time>
<day id="4"/>
<time>8:28</time >
<length>2000</length>
</time>
<time>
<day id="5"/>
<time>3:03</time >
<length>1000</length>
</time>
</times>
</person>
<person id="2">
<periods>3</periods>
<name id="James"/>
<times>
<time>
<day id="3"/>
<time>45:20</time >
<length>15000</length>
</time>
<time>
<day id="5"/>
<time>4:48</time >
<length>1500</length>
</time>
</times>
</person>
etc…
etc…
</persons>
Every person has one or more time-elements. I want to convert the structure so I get only one time-element per person-element (like the structure below).
 
<?xml version="1.0"?>
<persons>
<person id="1">
<periods>3</periods>
<name id="John"/>
<times>
<time>
<day id="1"/>
<time>35:28</time >
<length>8000</length>
</time>
</times>
</person>
<person id="1">
<periods>3</periods>
<name id="John"/>
<times>
<time>
<day id="4"/>
<time>8:28</time >
<length>2000</length>
</time>
</times>
</person>
<person id="1">
<periods>3</periods>
<name id="John"/>
<times>
<time>
<day id="5"/>
<time>3:03</time >
<length>1000</length>
</time>
</times>
</person>
<person id="2">
<periods>2</periods>
<name id="James"/>
<times>
<time>
<day id="3"/>
<time>45:20</time >
<length>15000</length>
</time>
</times>
</person>
<person id="2">
<periods>2</periods>
<name id="James"/>
<times>
<time>
<day id="5"/>
<time>4:48</time >
<length>1500</length>
</time>
</times>
</person>
</persons>
Is there a way to do this?

I really know English very bad, but I'll try to answer :)
I think, that for the implementation of this task will suit SimpleXml and Dom extensions.
The following is a simple script that does the required transformation.
input.xml is the file with source text.
The result of the algorithm will be saved to output.xml file.
<?php
$simpleXml = new SimpleXMLElement(file_get_contents('input.xml'));
$personElements = $simpleXml->person;
$personForAppend = array();
$personsForRemove = array();
foreach ($personElements as $personElement) {
$timeElements = $personElement->times->xpath("child::time");
$numberOfTimeElements = count($timeElements);
if ($numberOfTimeElements > 1) {
$personDomElement = dom_import_simplexml($personElement);
$backupTimeDomElementArray = array();
foreach ($timeElements as $timeElement) {
$timeDomElement = dom_import_simplexml($timeElement);
$backupTimeDomElementArray[] = clone $timeDomElement;
$timeDomElement->parentNode->removeChild(
$timeDomElement
);
}
while ($timeDomElement = array_shift($backupTimeDomElementArray)) {
$copyPersonDomElement = clone $personDomElement;
$copyPersonDomElement->getElementsByTagName('times')
->item(0)->appendChild($timeDomElement);
$personForAppend[] = $copyPersonDomElement;
}
$personsForRemove[] = $personDomElement;
}
}
foreach ($personForAppend as $personDomeNode) {
$personDomElement->parentNode->appendChild($personDomeNode);
}
foreach ($personsForRemove as $personDomElement) {
$personDomElement->parentNode->removeChild($personDomElement);
}
$simpleXml->saveXML('output.xml');

Related

XML strings to echo PHP

I have a sophisticated feed that I want to echo the values of the XML file to PHP table.
Below is a sample of the UK RailDataFeed (Aka Darwin).
<?xml version="1.0" encoding="UTF-8"?>
<Pport xmlns="http://www.thalesgroup.com/rtti/PushPort/v12" xmlns:ns3="http://www.thalesgroup.com/rtti/PushPort/Forecasts/v2" ts="2018-01-01T21:58:48.2213864Z" version="12.0">
<uR updateOrigin="Trust">
<TS>
<Location pta="21:59" ptd="21:59" tpl="ROBY" wta="21:59" wtd="21:59:30">
<arr at="21:59" src="TRUST" srcInst="Auto" />
<dep et="21:59" src="Darwin" />
<plat conf="true" platsrc="A">4</plat>
</Location>
<Location pta="22:06" ptd="22:06" tpl="PRESCOT" wta="22:05:30" wtd="22:06">
<arr et="22:06" src="Darwin" wet="22:05" />
<dep et="22:06" src="Darwin" />
<plat>1</plat>
</Location>
</TS>
</uR>
</Pport>
I have been trying and researching all day to try to get the echo working but without any luck, I have tried the following
Test (1)
$xml=simplexml_load_file("log.xml") or die("Error: Cannot create object");
echo $xml->Location[0]['tpl'] . "<br>";
echo $xml->Location[1]->arr['at'];
echo $xml->Location[2]->dep['et'];
echo $xml->Location[3]->plat;
Test (2)
$xml=simplexml_load_file("log.xml") or die("Error: Cannot create object");
foreach($xml->children() as $loc) {
echo $loc->Location['tpl'];
echo $loc->arr['at'];
echo $loc->plat;
echo "<br>";
}
Test (3)
$file = file_get_contents('log.xml');
echo $file;
Still without any progress, After achieving this, I want to add the values to a bootstrap table too.
If any Ideas please share with me.
You can access attribute values via the attributes() method. Also, note that values are cast to string when echoing.
$str = <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<Pport xmlns="http://www.thalesgroup.com/rtti/PushPort/v12" xmlns:ns3="http://www.thalesgroup.com/rtti/PushPort/Forecasts/v2" ts="2018-01-01T21:58:48.2213864Z" version="12.0">
<uR updateOrigin="Trust">
<TS>
<Location pta="21:59" ptd="21:59" tpl="ROBY" wta="21:59" wtd="21:59:30">
<arr at="21:59" src="TRUST" srcInst="Auto" />
<dep et="21:59" src="Darwin" />
<plat conf="true" platsrc="A">4</plat>
</Location>
<Location pta="22:06" ptd="22:06" tpl="PRESCOT" wta="22:05:30" wtd="22:06">
<arr at="22:06" src="Darwin" wet="22:05" />
<dep et="22:06" src="Darwin" />
<plat>1</plat>
</Location>
</TS>
</uR>
</Pport>
EOF;
$xml = simplexml_load_string($str);
$c = 0;
foreach($xml->uR->TS->Location as $loc) {
echo (++$c) . "\n";
echo (string)$loc->attributes()['tpl'] . "\n";
echo (string)$loc->arr->attributes()['at'] . "\n";
echo (string)$loc->dep->attributes()['et'] . "\n\n";
}
After #marekful reply.
code modified to
<?php
$str = file_get_contents('log.xml');
$xml = simplexml_load_string($str);
$c = 0;
foreach($xml->uR->TS->Location as $loc)
{
echo (++$c) . "\n";
echo (string)$loc->attributes()['tpl'] . "\n";
echo (string)$loc->arr->attributes()['at'] . "\n";
echo (string)$loc->dep->attributes()['et'] . "\n\n";
echo (string)$loc->plat . "\n\n\n";
}
?>
And it worked perfectly with the sample xml file, but after adding the original XML file, It has multiple header in the file itself as shown below:
<?xml version="1.0" encoding="UTF-8"?>
<Pport xmlns="http://www.thalesgroup.com/rtti/PushPort/v12" xmlns:ns3="http://www.thalesgroup.com/rtti/PushPort/Forecasts/v2" ts="2018-01-03T01:31:28.3036616Z" version="12.0">
<uR requestID="AM02050384" requestSource="AM02" updateOrigin="CIS">
<TS rid="201801037171519" ssd="2018-01-03" uid="G71519">
<ns3:Location tpl="GLYNDE" wtp="01:25:08">
<ns3:pass at="01:31" src="TD" />
<ns3:plat conf="true" platsrc="A" platsup="true">2</ns3:plat>
<ns3:length>8</ns3:length>
</ns3:Location>
</TS>
</uR>
</Pport>
<?xml version="1.0" encoding="UTF-8"?>
<Pport xmlns="http://www.thalesgroup.com/rtti/PushPort/v12" xmlns:ns3="http://www.thalesgroup.com/rtti/PushPort/Forecasts/v2" ts="2018-01-03T01:31:29.1772672Z" version="12.0">
<uR requestID="0000000000046386" requestSource="at21" updateOrigin="CIS">
<TS rid="201801038706030" ssd="2018-01-03" uid="W06030">
<ns3:Location pta="01:25" ptd="01:26" tpl="DARTFD" wta="01:25" wtd="01:26">
<ns3:arr at="01:31" src="TD" />
<ns3:dep et="01:32" etmin="01:27" src="Darwin" />
<ns3:plat conf="true" platsrc="A">4</ns3:plat>
</ns3:Location>
</TS>
</uR>
</Pport>
<?xml version="1.0" encoding="UTF-8"?>
<Pport xmlns="http://www.thalesgroup.com/rtti/PushPort/v12" xmlns:ns3="http://www.thalesgroup.com/rtti/PushPort/Forecasts/v2" ts="2018-01-03T01:31:30.1912737Z" version="12.0">
<uR updateOrigin="TD">
<TS rid="201801027160109" ssd="2018-01-02" uid="G60109">
<ns3:Location tpl="BRINKLW" wtp="01:34:30">
<ns3:pass at="01:31" src="TD" /></ns3:Location>
</TS>
</uR>
</Pport>
<?xml version="1.0" encoding="UTF-8"?>
<Pport xmlns="http://www.thalesgroup.com/rtti/PushPort/v12" xmlns:ns3="http://www.thalesgroup.com/rtti/PushPort/Forecasts/v2" ts="2018-01-03T01:31:31.2052802Z" version="12.0">
<uR updateOrigin="TD">
<TS rid="201801036763188" ssd="2018-01-03" uid="C63188">
<ns3:Location tpl="AMBERGJ" wtp="02:04:30">
<ns3:pass et="01:38" src="TD" /></ns3:Location>
</TS>
</uR>
</Pport>
Is there a way to:
Ignore the multiple headers to avoid errors.
Post the echo value to a Bootstrap table.
Cheers!

Delete an item by id in XML with PHP

I want to delete a node by id in XML my code is this:
$id=$_GET["id"];
$usuarios= simplexml_load_file('cart.xml');
if($_GET["action"] == "delete"){
foreach($usuarios->carro as $elemento){
if($elemento['id'] == $id) {
echo '<script>alert("delete")</script>';
unset($elemento['id']);
}
}
}
but doesn't work.
My XML cart.xml:
<?xml version="1.0"?>
<info>
<carro id="0">
<usuario>alex</usuario>
<producto>instict</producto>
<Size>CH</Size>
<cantidad>1</cantidad>
<precio>100</precio>
</carro>
<carro id="1">
<usuario>alex</usuario>
<producto>instict</producto>
<Size>G</Size>
<cantidad>1</cantidad>
<precio>100</precio>
</carro>
<carro id="2">
<usuario>alex</usuario>
<producto>instict</producto>
<Size>G</Size>
<cantidad>1</cantidad>
<precio>100</precio>
</carro>
<carro id="3">
<usuario>Gera</usuario>
<producto>instict</producto>
<Size>M</Size>
<cantidad>1</cantidad>
<precio>100</precio>
</carro>
</info>
I want to delete for example id="2" so the output would be:
<?xml version="1.0"?>
<info>
<carro id="0">
<usuario>alex</usuario>
<producto>instict</producto>
<Size>CH</Size>
<cantidad>1</cantidad>
<precio>100</precio>
</carro>
<carro id="1">
<usuario>alex</usuario>
<producto>instict</producto>
<Size>G</Size>
<cantidad>1</cantidad>
<precio>100</precio>
</carro>
<carro id="3">
<usuario>Gera</usuario>
<producto>instict</producto>
<Size>M</Size>
<cantidad>1</cantidad>
<precio>100</precio>
</carro>
</info>
Change
$usuarios->carro as $key => $elemento
and then
unset($usuarios->carro[$key]);
and then write result in new file as string
file_put_contents('newfile.xml', $usuarios->asXML());

XML PHP Get children value

XML:
<Result xmlns="" xmlns:xsi="" totalResultsAvailable="0" totalResultsReturned="0" schk="true" totalLooseOffers="0" xsi:schemaLocation="">
<details>
<ID></ID>
<applicationVersion>1.0</applicationVersion>
<applicationPath/>
<date>2016-05-23T12:17:16.369-03:00</date>
<elapsedTime>17</elapsedTime>
<status>success</status>
<message>success</message>
</details>
<category id="1">
<thumbnail url="http://image.google.com/test.jpg"/>
<links>
<link url="www.google.com" type="category"/>
<link url="www.google2.com" type="xml"/>
</links>
<name>Category</name>
<filters>
<filter id="1" name="Filter1">
<value id="1" value="Test1"/>
<value id="2" value="Test2"/>
<value id="3" value="Test3"/>
</filter>
<filter id="2" name="Filter2">
<value id="1" value="Test4"/>
<value id="2" value="Test5"/>
<value id="3" value="Test6"/>
</filter>
</filters>
</category>
</Result>
PHP:
$xml = simplexml_load_file("http://xml.com");
foreach($xml->category->filters as $filters){
foreach($filters->children() as $child){
echo $child['value'];
}
}
I'm trying to get the filters value, but nothing shows with the code i have. I saw something about xpath but don't know if it's applicable in this situation. Do you have any clue?
--
When the XML looks like this:
<Result xmlns="" xmlns:xsi="" totalResultsAvailable="0" totalResultsReturned="0" schk="true" totalLooseOffers="0" xsi:schemaLocation="">
<details>
<ID></ID>
<applicationVersion>1.0</applicationVersion>
<applicationPath/>
<date>2016-05-23T12:17:16.369-03:00</date>
<elapsedTime>17</elapsedTime>
<status>success</status>
<message>success</message>
</details>
<subCategory id="1">
<thumbnail url="http://image.google.com/test.jpg"/>
<name>Subcategory</name>
</subCategory>
<subCategory id="2">
<thumbnail url="http://image.google.com/test2.jpg"/>
<name>Subcategory2</name>
</subCategory>
</Result>
Then am able to do this:
foreach($xml->subCategory as $subCategory){
$categoryId = $subCategory['id'];
$categoryName = $subCategory->name;
}
The elements you reference as $child in the inner loop actually point to the <filter> nodes, not the children <value> nodes you are attempting to target attributes for. So this really is just a matter of extending the outer foreach loop to iterate over $xml->category->filters->filter rather than its parent $xml->category->filters.
// Iterate the correct <filter> node, not its parent <filters>
foreach ($xml->category->filters->filter as $filter) {
foreach($filter->children() as $child){
echo $child['value'] . "\n";
}
}
Here it is in demonstration: https://3v4l.org/Rqc4Y
Using xpath, you can target the inner nodes directly.
$values = $xml->xpath('//category/filters/filter/value');
foreach ($values as $value) {
echo $value['value'];
}
https://3v4l.org/vPhKE
Both of these examples output
Test1
Test2
Test3
Test4
Test5
Test6

php create xml CDATA on loop

want to make loop and Parsing XML CDATA
my XML
<?xml version="1.0"?>
<photos>
<photo image="images/1.jpg" url="http://LINKHERE" target="_blank" id="1">
</photo>
<photo image="images/1.jpg" url="http://LINKHERE" target="_blank" id="2">
</photo>
</photos>
my code
for ($x = 1; $x <= 10; $x++) {
$dom=new DOMDocument();
$xml='images.xml';
$dom->load($xml);
$xp = new DomXPath($dom);
//$item_content = $xp->query("//*[#id = $x]");
foreach ($dom->getElementsByTagName('photos') as $item) {
$cdata=$dom->createCDATASection('<head>test'.$x.'</head><body></body>');
$item->getElementsByTagName('photo')->item(0)->appendChild($cdata);
}
$dom->save($xml);
}
but the result
<photo image="images/1.jpg" url="http://LINKHERE" target="_blank" id="1">
<![CDATA[<head>test1</head><body></body><head>test2</head><body></body><head>test3</head><body></body>
<head>test4</head><body></body><head>test5</head><body></body>
<head>test6</head><body></body><head>test7</head>
<body></body><head>test8</head><body></body><head>test9</head><body></body>]]><![CDATA[<head>test10</head><body>
</body>]]></photo>
<photo image="images/2.jpg" url="http://http://LINKHERE" target="_blank" id="2">
</photo>
i want it be this
<photo image="images/1.jpg" url="http://LINKHERE" target="_blank" id="1">
<![CDATA[<head>test1</head><body></body>]]></photo>
<photo image="images/2.jpg" url="http://http://LINKHERE" target="_blank" id="2">
<![CDATA[<head>test2</head><body></body>]]></photo>
i want move on loop by id
i try many times but no way , i think i have a problem on my loop
need some help here
You want to append CData on each photo element, so you should loop through photo instead of photos, for example :
$raw = <<<XML
<photos>
<photo image="images/1.jpg" url="http://LINKHERE" target="_blank" id="1">
</photo>
<photo image="images/1.jpg" url="http://LINKHERE" target="_blank" id="2">
</photo>
</photos>
XML;
$dom = new DOMDocument();
$dom->loadXML($raw);
$x = 1;
foreach ($dom->getElementsByTagName('photo') as $item) {
$cdata=$dom->createCDATASection('<head>test'.$x.'</head><body></body>');
$item->appendChild($cdata);
$x++;
}
echo $dom->saveXML($xml);
eval.in demo
output :
<?xml version="1.0"?>
<photos>
<photo image="images/1.jpg" url="http://LINKHERE" target="_blank" id="1">
<![CDATA[<head>test1</head><body></body>]]></photo>
<photo image="images/1.jpg" url="http://LINKHERE" target="_blank" id="2">
<![CDATA[<head>test2</head><body></body>]]></photo>
</photos>
Try this code
<?php
$dom=new DOMDocument();
$xml='images.xml';
$dom->load($xml);
$xp = new DomXPath($dom);
$i = 0;
foreach ($dom->getElementsByTagName('photo') as $item) {
$cdata=$dom->createCDATASection('<head>test'.($i+1).'</head><body></body>');
$item->appendChild($cdata);
$i ++;
}
$dom->save($xml);

Delete Node if Child is empty with php?

I want to be able to to delete a node tree if a specific child is empty, but seems to do something wrong?
Here is what I got:
$xml = new DOMDocument();
$xml->loadXML('<?xml version="1.0" encoding="ISO-8859-1"?>
<data>
<game id="1">
<opponent>Michael</opponent>
<oppid>1</oppid>
</game>
<game id="2">
<opponent>Trish</opponent>
<oppid>55</oppid>
</game>
<game id="3">
<opponent/>
<oppid>24</oppid>
</game>
<game id="4">
<opponent>Betty</opponent>
<oppid>12</oppid>
</game>
</data>
');
echo "<xmp>OLD \n". $xml->saveXML() ."</xmp>";
$xpath = new DOMXpath($xml);
foreach($xpath->query('//game') as $node) {
if($node->opponent == ''){
echo 'Test<br>';
$node->parentNode->removeChild($node);
}
}
echo "<xmp>NEW \n". $xml->saveXML() ."</xmp>";
I get 4 "Test" printed out and in the NEW xmp I get nothing? What am I doing wrong?
Please help and thanks in advance.
<?php
$xml = new DOMDocument();
$xml->loadXML('<?xml version="1.0" encoding="ISO-8859-1"?>
<data>
<game id="1">
<opponent>Michael</opponent>
<oppid>1</oppid>
</game>
<game id="2">
<opponent>Trish</opponent>
<oppid>55</oppid>
</game>
<game id="3">
<opponent/>
<oppid>24</oppid>
</game>
<game id="4">
<opponent>Betty</opponent>
<oppid>12</oppid>
</game>
</data>
');
echo "<xmp>OLD \n". $xml->saveXML() ."</xmp>";
$opNodes = $xml->getElementsByTagName('opponent');
foreach($opNodes as $node) {
$innerHtml = trim($node->nodeValue);
if(empty($innerHtml)){
$gameNode = $node->parentNode;
$gameNode->parentNode->removeChild($gameNode);
}
}
echo "<xmp>NEW \n". $xml->saveXML() ."</xmp>";
i wonder why it was not working... now it works .
Change your if condition to following:
if($node->opponent->nodeValue == '')

Categories