I am trying to edit an XML document using PHP, but it does not seem to work, wonder where I am going wrong!
I am trying to do it the following way which I found online. Can anyone please show me the right direction?
XML
<gold>
<coin>
<id>1</id>
<title>Gold Coin 50 Grams</title>
<price>500 rupees</price>
<dimension>20 MM</dimension>
<thumb_url>http://animsinc.com/Expertise-media.png</thumb_url>
</coin>
<coin>
<id>2</id>
<title>Gold Coin 50 Grams</title>
<price>500 rupees</price>
<dimension>20 MM</dimension>
<thumb_url>
http://animsinc.com/Expertise-media.png</thumb_url>
</coin>
...
</gold>
PHP Code
$xmlDoc = new DOMDocument();
$xmlDoc->loadXml($str);
$events = $xmlDoc->getElementsByTagName("coin");
foreach($events as $event){
$eventNames = $event->getElementsByTagName("price");
$eventN = $eventNames->item(0)->nodeValue;
if('500' == $eventN){ // ** Failed here, instead of '500',
// I used '500 rupees' and it worked, as that matches the original text.**
$eventNames->item(0)->nodeValue = $rest ;
}
}
var_dump($xmlDoc->saveXML());
Here's the desired result. Notice how I've changed the price tag to 2495 rupees.
<gold>
<coin>
<id>1</id>
<title>Gold Coin 50 Grams</title>
<price>2495 rupees</price>
<dimension>20 MM</dimension>
<thumb_url>http://animsinc.com/Expertise-media.png</thumb_url>
</coin>
<coin>
<id>2</id>
<title>Gold Coin 50 Grams</title>
<price>2495 rupees</price>
<dimension>20 MM</dimension>
<thumb_url>
http://animsinc.com/Expertise-media.png</thumb_url>
</coin>
...
</gold>
Here's a quick solution based on SimpleXML:
$gold = new SimpleXMLElement($xml);
foreach ($gold->coin as $coin) {
$coin->price = str_replace('500', $rest, (string) $coin->price);
}
echo $gold->asXML();
Working demo.
Oh hey, it was a mistake on my part, the function works perfect, instead of
if('500' == $eventN)
The Correct woulld be
if('500 rupees' == $eventN)
Dumb
Related
Given the XML and related PHP, below how can I get the namespaced values in the same way that I'm able to get the non-namespaced values? I've been referring to a number of other SE QAs about this, but can't seem to get it right. An help is appreciated. :)
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:psg="http://b3000.example.net:3000/psg_namespace/">
<channel>
<title>Example</title>
<description>example stuff</description>
<item>
<psg:eventId>406589</psg:eventId>
<psg:duration>3482</psg:duration>
</item>
</channel>
</rss>
$xml = new SimpleXMLElement($source, null, true);
foreach($xml->channel->item as $entry){
echo $entry->title; // This works
echo $entry->description; // This works
echo $entry->item->duration // Pseudo of what I need
}
How to get Duration? My attempts with variations such as this have failed
$namespaces = $item->getNameSpaces(true);
$psg = $item->children($namespaces['psg']);
Update
While it wasn't the answer I was actually looking for, I have to accept the first answer that got me trying things leading to the actual problem - "operator error"! This DOES work....my problem was in trying to figure it out, I was debugging with echo print_r($psg, true). That was showing the result as a SimpleXmlObject, which then got me chasing how to get those properties - All I had to do was assign the property instead of echoing it.
foreach($xml->channel->item as $entry){
$psg = $item->children($ns['psg']);
$title = (string) $item->title;
$duration = (string) $psg->duration;
}
One way to achieve this is to use a combination of XPath with namespaces:
$xml = new SimpleXMLElement($source, null, true);
$xml->registerXPathNamespace('psg', 'http://b3000.example.net:3000/psg_namespace/');
foreach ($xml->xpath('//item/psg:duration') as $duration) {
echo $duration, PHP_EOL;
}
If you don't want to declare the namespace literally, you can retrieve it from the document and add it/them dynamically:
foreach ($xml->getDocNamespaces() as $key => $namespace) {
$xml->registerXPathNamespace($key, $namespace);
}
I wrote a code according to which I can write one XML file into number of XML files depending on number of records.
I have 14 records in one XML file having different tags in XML file.
I am trying to create XML files having having 2 records each, so in the end I should be having 7 XML files.
But instead that I'm getting 14 files only, each file having two similar records.
Following is my XML format, which is getting created dynamically. Format is coming correctly. But two similar entries are coming in each file. So instead of 7 its writing 14 files.
<?xml version="1.0"?>
<data>
<Product>
<PID>SGLDN7XJ2FPZH8G8</PID>
<PNAME>Miami Blues Aviator Sunglasses</PNAME>
</Product>
</data>
Following is my file which is making XML files. I think something is wrong in initializing the for loop:
$docOutput = new DOMDocument("1.0");
$root = $docOutput->createElement("data");
$docOutput->appendChild($root);
if (!$sxmlReading = simplexml_load_file('firstxml.xml')) {
throw new RuntimeException('Error reading XML file');
}
$x = 0;
foreach ($sxmlReading as $syn) {
for ($i = $x * 2; $i < ($x + 1) * 2; $i++) {
$id = $docOutput->createElement("PID");
$idText = $docOutput->createTextNode($syn->productId);
$id->appendChild($idText);
$title = $docOutput->createElement("PNAME");
$titleText = $docOutput->createTextNode($syn->productname);
$title->appendChild($titleText);
$book = $docOutput->createElement("Product");
$book->appendChild($id);
$book->appendChild($title);
$root->appendChild($book);
$docOutput->formatOutput = true;
echo "<xmp>" . $docOutput->saveXML() . "</xmp>";
$docOutput->save("xml$x.xml") or die("Error");
}
$x++;
}
Please check the code and highlight my mistake...
It is writing 14 files because you are calling the DOMDocument::save() method 14 times.
Sounds more like a typo to me honestly, I can not see anything wrong with that. PHP just does as you've written it to do.
I have problems to deal with XML in PHP. What i want is to remove a not needed element and replace it with a other one.
Let's say the XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<software>
<info>
<version>1.2</version>
<lasterror>1386680712</lasterror>
</info>
<decryption>
<funcgroup siglength="86">
<func>
<name>Mk</name>
<args>$a</args>
<code>XXXX</code>
</func>
<func>
<name>Nk</name>
<args>$a,$b</args>
<code>XXXX</code>
</func>
</funcgroup>
</decryption>
</software>
PHP Code:
$domtree = new DOMDocument('1.0', 'UTF-8');
$domtree->loadXML(file_get_contents('test.xml'));
$thedocument = $domtree->documentElement;
$list = $thedocument->getElementsByTagName('funcgroup');
foreach ($list as $domElement) {
$sig_length = $domElement->getAttribute('siglength');
if($sig_length == $signature_length) {
$domElement->parentNode->removeChild($domElement);
break;
}
}
$some_stuff = $domtree->getElementsByTagName('software');
$some_stuff = $domtree->getElementsByTagName('decryption');
$funcgroup = $domtree->appendChild($domtree->createElement('funcgroup'));
$funcgroup->setAttribute('siglength', $signature_length);
$func = $funcgroup->appendChild($domtree->createElement('func'));
$func->appendChild($domtree->createElement('name', $outer_element[0]));
$func->appendChild($domtree->createElement('args', $outer_element[1]));
$code = $func->appendChild($domtree->createElement('code'));
$code->appendChild($domtree->createTextNode($outer_element[2]));
Note: I removed some stuff otherwise it would get too complicated i guess. The above code shows what i do, but without some other loops and variables which are not needed in that question. Every variable (and array) is defined. So don't worry about that.
What i want is to remove the whole <funcgroup siglength="86"> in order to replace it with a different one.
The script works fine, but there is one problem in the output XML. It looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<software>
<info>
<version>6.3</version>
<lasterror>1386680712</lasterror>
</info>
<decryption/>
</software>
<funcgroup siglength="86">
<func>
<name>Nk</name>
<args>$a</args>
<code>YYYYY</code>
</func>
<func>
<name>Ok</name>
<args>$a,$b</args>
<code>YYYY</code>
</func>
</funcgroup>
As you can see, the closing software and decryption tags are on the wrong place now.
How can i fix that? I spent hours but can't find a working solution.
The problem is caused by the removeChild() since it works fine if i do not remove something.
You are adding your new child node to the document itself (instead of the decryption node), which is not what you want
$domtree->appendChild
Instead you should:
$decryption = $domtree->getElementsByTagName('decryption')->item(0);
$funcgroup = $decryption->appendChild($domtree->createElement('funcgroup'));
Edit:
You can edit the text value of the lasterror node by doin:
$domtree->getElementsByTagName('lasterror')->item(0)->firstChild->nodeValue = "New value";
Consult the documentation of the DOMNodeList and DOMNode class to see what else you can do with it.
I have some problems making a function to replace question and answer elements in my XML file. I did alot of research learning php dom but I'm running stuck at making this function. The problem is that when I'm trying to get the parent element row by attribute id it returns null or when I use xpath it returns an empty object. I don't know if the function will work correct after I get the the right parent element but that's the next step I think.
my XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<row id="1">
<question>Wat doet de vuilnisman?</question>
<answer>Hij tilt de vuilnisbak in de vuilnisauto.</answer>
</row>
<row id="2">
<question>Wat zegt de tandarts vaak?</question>
<answer>U mag nu spoelen.</answer>
</row>
</root>
and my php function:
//modifies rows
function modifyRows($file, $rowIds, $rowText) {
$xmlDoc = new DOMDocument();
$xmlDoc->preserveWhiteSpace = false;
$xmlDoc->formatOutput = true;
$xmlDoc->load($file);
foreach($rowIds as $rowId) {
$parent = $xmlDoc->getElementById($rowId);
for($i=0;$i<count($rowText);$i++) {
$newQ = $xmlDoc->createElement('question');
$qText = $xmlDoc->createTextNode($rowText[$i]);
$qText = $newQ->appendChild($qText);
$newA = $xmlDoc->createElement('answer');
$aText = $xmlDoc->createTextNode($rowText[$i++]);
$aText = $newA->appendChild($aText);
}
$oldQ = $parent->getElementsByTagName('question');
$oldA = $parent->getElementsByTagName('answer');
$parent->replaceChild($newQ, $oldQ);
$parent->replaceChild($newA, $oldA);
}
$xmlDoc->save($file);
}
$rowIds is an array which contains the numbers of the rows that where modified ans rowText in an array which contains the question and answer strings like array(0=>"question",1=>"answer") and so on. The XML file content can get bigger or smaller by adding or removing rows. I have already made "working" functions for that.
I have solved the problem thanx to hakre and the internet. So for people with the same problem this is how I solved it.
function getElementById($id) {
$xpath = new DOMXPath($this->xmlDoc);
return $xpath->query("//*[#id='$id']")->item(0);
}
I am making a simple web-based application that shows the arrival time (in minutes) of trains arriving at the metro station near my home.
Metro (The subway in Washington, DC) has released an API that allows developers to access this information: http://developer.wmata.com/docs/read/GetRailStationInfo
When I use the example code from the link above I get a list of tagged text like this:
<AIMPredictionResp xmlns="http://www.wmata.com" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Trains>
<AIMPredictionTrainInfo>
<Car>6</Car>
<Destination>NewCrltn</Destination>
<DestinationCode>D13</DestinationCode>
<DestinationName>New Carrollton</DestinationName>
<Group>1</Group>
<Line>OR</Line>
<LocationCode>K03</LocationCode>
<LocationName>Virginia Square</LocationName>
<Min>7</Min>
</AIMPredictionTrainInfo>
</Trains>
All I want to display is the minutes wrapped in the < Min > < /Min > tag. What's the best way to go about this? Is there a PHP script that I can write that will pull just that number? If so, could you please point me in the right direction?
Thanks!
UPDATE:
Thank you all very much. I have tried an example from the tutorial you sent, but when I switch my URL (with key) in it does not display anything.
<?php
$trainInfo = simplexml_load_file("api.wmata.com/StationPrediction.svc/GetPrediction/_KEYXXXXXXXX);
print $trainInfo->AIMPredictionTrainInfo->LocationName;
print $trainInfo->AIMPredictionTrainInfo->Min;
?>
The direction you want to be pulled in is SimpleXML
EXAMPLE (not tested):
<?php
$xml = new SimpleXMLElement($my_input_xml);
echo $xml->getMin() . "<br>";
?>
Here are some other good tutorials:
http://php.net/manual/en/simplexml.examples-basic.php
http://www.phpeveryday.com/articles/PHP-SimpleXML-Tutorial-P846.html
'Hope that helps!
Here comes an example using DOMXPath (tested). Important is to register the default namespace:
$data = <<<EOF
<?xml version="1.0"?>
<AIMPredictionResp xmlns="http://www.wmata.com" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Trains>
<AIMPredictionTrainInfo>
<Car>6</Car>
<Destination>NewCrltn</Destination>
<DestinationCode>D13</DestinationCode>
<DestinationName>New Carrollton</DestinationName>
<Group>1</Group>
<Line>OR</Line>
<LocationCode>K03</LocationCode>
<LocationName>Virginia Square</LocationName>
<Min>7</Min>
</AIMPredictionTrainInfo>
</Trains>
</AIMPredictionResp>
EOF;
$doc = new DOMDocument();
$doc->loadXML($data);
$selector = new DOMXPath($doc);
$selector->registerNamespace(
'default',
'http://www.wmata.com'
);
$query = '//default:Min';
foreach($selector->query($query) as $node) {
var_dump($node->nodeValue);
}
Output:
string(1) "7"