I am trying to add a child note to an XML file using PHP. I have used the same method about 5 times before and each one works as expected, however this method is using a different XML structure on a new file (which I think might be part of the problem).
The method causing me the problem is this:
function addCourseToProject($name, $project){
$projects = self::getRoles();
$theProject = $projects->xpath('project[name = "'.$project.'"]');
echo $theProject->name;
$theCourses = $theProject[0]->courses->addchild("course", $name);
$projects->asXml("projects.xml");
}
The XML file looks like this:
<projects>
<project>
<name>Alpha</name>
<courses>
<course>Beta</course>
<course>Charlie</course>
</courses>
</project>
</project>
And getRoles() looks like this:
function getRoles(){
$roles = simplexml_load_file("projects.xml") or die("ERROR: Unable to read file");
return $roles;
}
I'm at a loss here, I have no idea why this is different from the other adding functions (see below).
Should you need it, here is an example of what my other methods look like:
function addModule($courseName, $name, $link){
$xml = self::getXml();#get the xml file
$course = $xml->xpath('course[name = "'.$courseName.'"]');
$module = $course[0]->addChild("module");
$module->addChild("name", $name);
$module->addChild("link", $link);
$xml->asXml("data.xml");
echo self::toJSON($course);
}
and the getXML() method:
function getXml(){
$xml=simplexml_load_file("data.xml") or die("ERROR: Unable to read file");
return $xml;
}
Turned out that the problem was caused by the fact that <project> element is nested within the XML document. You can use descendant-or-self axis (// for the abbreviated syntax) to get nested element like so :
$theProject = $projects->xpath('//project[name = "'.$project.'"]');
or specify the complete path :
$theProject = $projects->xpath('/projects/project[name = "'.$project.'"]');
Related
I am working currently on an OOP based PHP project in MVC style.
For my project i need to create/send/recieve/process XMLs.
Now i have a BIG problem with creating XML-Structures with DOMDocument.
Everytime i create a new XML-Node without an attributes or values, all nodes afterwards will be a child if this node!
In other words: I can not create an empty XML-Node without all nodes afterwards beeing a child of this empty node!!!
This problem bugs me for while now but I really need the way I am dealing right now with the XML creation.
I couldn't find any solutions but some similar problems.
This PHP tests my XmlHandler-Class, which creates the XML-Request:
Test.php:
<?php
include "Handler/XmlHandler.php";
$xmlHandler=new XmlHandler();
$xmlHandler->CreateNewXmlInstance();
$root = $xmlHandler->CreateRootNode('RootNode');
$l1 = $xmlHandler->AppendNodeWithChild($root, "NodeLevel1", "Text1 - This node one has text");
$l2 = $xmlHandler->AppendNodeWithChild($root, "NodeLevel2", "Text2 - Next node Level3 level is not gonna have text");
$l21 = $xmlHandler->AppendNodeWithChild($l2, "NodeLevel2_1", "Text2_1 - This node will be a child of Level2, everything fine");
$l3 = $xmlHandler->AppendNodeWithChild($root, "NodeLevel3", "");
$l4 = $xmlHandler->AppendNodeWithChild($root, "NodeLevel4", "Text4 - This node should be on same level like 3, 2 & 1, but instead it's a child of Level 3 (?!?!?!?!)");
echo "<p style='display:none;'>".$xmlHandler->SaveXml()."</p>";
?>
Here is the XML-Handler Class which i use to create the XML-Request-Structure (i just posted the neccessary parts of the class here)
XmlHandler.php:
<?php
class XmlHandler{
private $xml;
/**
*
* Constructor
*
*/
function __construct()
{
$this->xml=null;
}
//[...]
/*
* Custom XML-Creator Functions
*
*/
public function CreateNewXmlInstance(){
/*********************************************/
/** XML DOM example of building XML Request **/
/*********************************************/
$this->xml = new DOMDocument('1.0', 'UTF-8');
return $this->xml;
}
public function CreateRootNode($name){
$rootElement = $this->xml->appendChild( $this->xml->createElement($name) );
return $rootElement;
}
public function AppendNodeWithChild($node, $childName, $childText){
$result = $node->appendChild($this->xml->createElement($childName));
if(null != $childText && !empty($childText)){
$result->appendChild( $this->xml->createTextNode($childText) );
}
return $result;
}
public function SetNodeAttributes($node, $nameAndValues){
if(null != $nameAndValues && sizeof($nameAndValues) > 0){
foreach($nameAndValues as $name => $value){
$this->SetNodeAttribute($node, $name, $value);
}
}
}
public function SetNodeAttribute($node, $name, $value){
$node->setAttribute($name, $value);
}
public function SaveXml(){
return $this->xml->saveXML();
}
//[...]
}
?>
This is the Result:
<!-- ?xml version="1.0" encoding="UTF-8"? -->
<rootnode>
<nodelevel1>Text1 - This node one has text</nodelevel1>
<nodelevel2>Text2 - Next node Level3 level is not gonna have text
<nodelevel2_1>Text2_1 - This node will be a child of Level2, everything fine</nodelevel2_1>
</nodelevel2>
<nodelevel3>
<nodelevel4>Text4 - This node should be on same level like 3, 2 & 1, but instead it's a child of Level 3 (?!?!?!?!)</nodelevel4>
</nodelevel3>
</rootnode>
But in theory, there should be somethign like that:
<!-- ?xml version="1.0" encoding="UTF-8"? -->
<rootnode>
<nodelevel1>Text1 - This node one has text</nodelevel1>
<nodelevel2>Text2 - Next node Level3 level is not gonna have text
<nodelevel2_1>Text2_1 - This node will be a child of Level2, everything fine</nodelevel2_1>
</nodelevel2>
<nodelevel3/>
<nodelevel4>Text4 - This node should be on same level like 3, 2 & 1, but instead it's a child of Level 3 (?!?!?!?!)</nodelevel4>
</rootnode>
As you can see: Something went wrong when i had not set a value for the new created Node on Level3!:
$l3 = $xmlHandler->AppendNodeWithChild($root, "NodeLevel3", "");
$l4 = $xmlHandler->AppendNodeWithChild($root, "NodeLevel4", "Text4 - This node should be on same level like 3, 2 & 1, but instead it's a child of Level 3 (?!?!?!?!)");
As long as i set attributes or put in value sin the new created node, everything is fine.
But i have some situations where also pure empty nodes have to be created!
My question is:
What am I doing wrong here?
Or does PHP do something wrong?
Maybe my browser does a bad preparation of the XML, but the outgoing XML request was build and send correctly and the mistake lies something else?
If so, how can I check the XML request though?
Edit Nr.2:
I changed my question/original post somehow.
The above example is a bit more easy to understand.
At least i hope so.
Wrap your helper functions in a class
class XMLHelper {
/*
* Custom XML-Creator Functions
*
*/
private $xml;
public function CreateNewXmlInstance(){
/*********************************************/
/** XML DOM example of building XML Request **/
/*********************************************/
$this->xml = new DOMDocument('1.0', 'UTF-8');
return $this->xml;
}
public function CreateRootNode($name){
$rootElement = $this->xml->appendChild( $this->xml->createElement($name) );
return $rootElement;
}
public function AppendNodeWithChild($node, $childName, $childText){
$result = $node->appendChild($this->xml->createElement($childName));
if(null != $childText && !empty($childText)){
$result->appendChild( $this->xml->createTextNode($childText) );
}
return $result;
}
public function SetNodeAttributes($node, $nameAndValues){
if(null != $nameAndValues && sizeof($nameAndValues) > 0){
foreach($nameAndValues as $name => $value){
$this->SetNodeAttribute($node, $name, $value);
}
}
}
public function SetNodeAttribute($node, $name, $value){
$node->setAttribute($name, $value);
}
public function SaveXml(){
return $this->xml->saveXML();
}
}
Wrap things in class because your code contain $this calls
Wrapping things in class make $this calls to correct variables the program needs.
Then new the class and initialize the nodes
$test = new XMLHelper();
$test->CreateNewXmlInstance();
$request = $test->CreateRootNode("request");
$node1 = $test->AppendNodeWithChild($request, "node1", null);
$node2 = $test->AppendNodeWithChild($node1, "node2", null);
$test->SetNodeAttributes($node2, array(
"client" => "This is a testing value"
));
echo $test->saveXml();
//Output:
// <?xml version="1.0" encoding="UTF-8"?>
// <request>
// <node1>
// <node2 client="This is a testing value"/>
// </node1>
// </request>
Please be noted that code need to executed in a correct sequence.
New the root node ( request )
Then append a node 1 to ( request )
Finally append node 2 to node 1
Configure the client value of node 2
Print out the whole root node
Then you've done the magic
There is nothing wrong with PHP neither with your web browser.
The error probably come from you haven't initialize the root node and not adding the created node correctly to the root node.
For XML validation in php, see this link.
DOMDocument has a function built-in for validation.
Edit 2016-08-10
Here are the revised code of your case
class SpecificXmlHandler extends XmlHandler{
/**
* Constructor
*
*/
private $errorCounter;
private $xmlUrl;
//Declare the root first
private $root;
function __construct()
{
parent::__construct();
$this->errorCounter=0;
$this->xmlUrl=Configuration::XML_REQUEST_URL;
}
//[...]
/**
* Action Functions
*/
public function GetStaticData($requestName, $requestFilterNamesAndValues){
$xml = $this->BuildStaticDataRequest($requestName, $requestFilterNamesAndValues);
echo "<p style='display:none'>" . $xml. "</p>"; //Request
$response = $this->ExecuteRequest($this->xmlUrl, $xml, null, false);
echo "<p style='display:none'>" . $response . "</p>"; //Resonse
//[...]
}
//[...]
/**
* Request Building Functions
*/
public function BuildStaticDataRequest($requestName, $requestFilterNamesAndValues){
$this->CreateNewXmlInstance();
//$root = $this->CreateRootNode('Request');
//Use the root node you have created in the constructor by using $this
$this->root = $this->CreateRootNode('Request');
//Generate Header (Source-Node)
$this->GenerateHeadData($this->root);
//[...]
return $this->SaveXml();
}
public function GenerateHeadData($root){
$clientID=Configuration::XML_CLIENT;
//Here the Node1 & Node2 creation
$node1 = $this->AppendNodeWithChild($root, "node1", null);
$node2 = $this->AppendNodeWithChild($node1, "node2", null);
$this->SetNodeAttributes( $node2 , array(
"Client" =>$clientID
));
//Change it to return the whole root
return $root;
}
[...]
}
Please create variables in the class and use $this to refer the private variables you have created.
Ok guys, somebody helped me with this problem.
Here is the conversation:
Him: The tags are wrong (since they've been changed to all-lowercase)
Me: Yes, it seems the XML gets messy after echoing it out into the browser instead of saving it into a file!
Him: And the output shouldn't even be formatted
Me: I did that myself for a better view
Him: This is the raw output of $xmlHandler->SaveXml() after enabling formatted output
<?xml version="1.0" encoding="UTF-8"?>
<RootNode>
<NodeLevel1>Text1 - This node one has text</NodeLevel1>
<NodeLevel2>Text2 - Next node Level3 level is not gonna have text<NodeLevel2_1>Text2_1 - This node will be a child of Level2, everything fine</NodeLevel2_1></NodeLevel2>
<NodeLevel3/>
<NodeLevel4>Text4 - This node should be on same level like 3, 2 & 1, but instead it's a child of Level 3 (?!?!?!?!)</NodeLevel4>
</RootNode>
Me: After printing it out into a file, i got the same result as you.
The conclusion:
Now I've wrote the saveXml-output into a file.
The Result is he same as Him told me.
So were was the mess?
I thoght it would be enough to print the XML out into the browser with echo and check it through the HTML-sourcecode via FireFox.
As you can see in my first post, i used echo...
echo "<p style='display:none;'>".$xmlHandler->SaveXml()."</p>";
to somehow print out the result of my XML-Creation (because i didn't know how else).
Therefore the XML-Creation was a full success from start up and the error i get from the response-Server lies somewhere else (from now on i can not rely on your help anymore)!
I'd like to get the text from the <Version> element which is nested inside the <service> block of a WSDL. The WSDL in question is Ebay's Trading api. The snippet in question looks something like this:
<wsdl:service name="eBayAPIInterfaceService">
<wsdl:documentation>
<Version>941</Version>
</wsdl:documentation>
<wsdl:port binding="ns:eBayAPISoapBinding" name="eBayAPI">
<wsdlsoap:address location="https://api.ebay.com/wsapi"/>
</wsdl:port>
</wsdl:service>
I'm currently doing this:
$xml = new DOMDocument();
$xml->load($this->wsdl);
$version = $xml->getElementsByTagName('Version')->item(0)->nodeValue;
This works but I'm wondering if there is a method to get this natively using PHP's SOAP extension?
I was thinking something like the following would work but it doesn't:
$client = new SoapClient($this->wsdl);
$version = $client->eBayAPIInterfaceService->Version;
It is not possible to do what you want with the regular SoapClient. Your best bet is to extend the SoapClient class and abstract-away this requirement to get the version.
Please beware that file_get_contents is not cached so it will always load the WSDL file. On the other hand SoapClient caches the WSDL so you will have to deal with it yourself.
Perhaps look into NuSOAP. You will be able to modify the code to suit your purposes without loading the WSDL twice (of course you are able to modify SoapClient too but that's another championship ;) )
namespace Application;
use DOMDocument;
class SoapClient extends \SoapClient {
private $version = null;
function __construct($wsdl, $options = array()) {
$data = file_get_contents($wsdl);
$xml = new DOMDocument();
$xml->loadXML($data);
$this->version = $xml->getElementsByTagName('Version')->item(0)->nodeValue;
// or just use $wsdl :P
// this is just to reuse the already loaded WSDL
$data = "data://text/plain;base64,".base64_encode($data);
parent::__construct($data, $options);
}
public function getVersion() {
return is_null($this->version) ? "Uknown" : $this->version;
}
}
$client = new SoapClient("http://developer.ebay.com/webservices/latest/ebaysvc.wsdl");
var_dump($client->getVersion());
Have you tried simplexml_load_file? Worked for me when i needed to parse an XML-File with php.
<?php
$file = "/path/to/yourfile.wsdl";
$xml = simplexml_load_file($file) or die ("Error while loading: ".$file."\n");
echo $xml->service->documentation->Version;
//if there are more Service-Elements access them via index
echo $xml->service[index]->documentation->Version;
//...where index in the number of the service appearing
//if you count them from top to buttom. So if "eBayAPIInterfaceService"
//is the third service-Element
echo $xml->service[2]->documentation->Version;
?>
My question is a rather simple one for anyone familiar with the DOM* classes in PHP.
Basically i have different classes that i want to return to me something that I can append in my xml document
Following pseudo-code should demonstrate better
Class ChildObject{ function exportToXML( return a DOMNode ? ) }
Class ContainerObject{
function exportToXML(){
$domSomething = new DOM*SOMETHING*;
foreach($children as $child) $domSomething->appendChild($child->exportToXML);
return $domSomething ;
}
}
Now i want to create the entire DOMDocument
$xml = new DOMDocument();
$root = $xml->createElement('root');
foreach($containers as $container) $root->appendChild($container->exportToXML());
I tried sending the DOMDocument object as a reference, did not work. I tried creating DOMNodes but didn't work as well....so i'm looking at a simple answer: what datatypes do i need to return in order for me to achieve the above functionality?
<?php
$xml = new DOMDocument();
$h = $xml->createElement('hello');
$node1 = new DOMNode('aaa');
$node1->appendChild(new DOMText('new text content'));
//node1 is being returned by a function
$node2 = new DOMNode('bbb');
$node2->appendChild(new DOMText('new text content'));
//node2 is being returned by some other function
$h->appendChild($node1);//append to this element the returned node1
$h->appendChild($node2);//append to this element the returned node2
$xml->appendChild($h);//append to the document the root node
$content = $xml->saveXML();
file_put_contents('xml.xml', $content);//output to an xml file
?>
The above code should do the following:
consider that i want to build the following xml
<hello>
<node1>aaa</node1>
<node2>bbb</node2>
</hello>
node1 could be again a node that has multiple children so node1 could be as well as something like this:
<node1>
<child1>text</child1>
<child2>text</child2>
<child3>
<subchild1>text</subchild1>
</child3>
</node1>
Basically when i call exportToXML() something should be returned, call it $x that i can append in my document using $xml->appendChild($x);
I want to create the above structure and return the object that can be appended in the DOMDocument
The following code:
<?php
$xml = new DOMDocument();
$h = $xml->appendChild($xml->createElement('hello'));
$node1 = $h->appendChild($xml->createElement('aaa'));
$node1->appendChild($xml->createTextNode('new text content'));
$node2 = $h->appendChild($xml->createElement('bbb'));
$node2->appendChild($xml->createTextNode('new text content'));
$xml->save("xml.xml");
?>
will produce:
<?xml version="1.0"?>
<hello>
<aaa>new text content</aaa>
<bbb>new text content</bbb>
</hello>
Your example XML showed <node1>aaa</node1> but I think your various code snippet examples went out of sync when you were editing =) In case you need that output, try:
<?php
$xml = new DOMDocument();
$h = $xml->appendChild($xml->createElement('hello'));
$node1 = $h->appendChild($xml->createElement('node1'));
$node1->appendChild($xml->createTextNode('aaa'));
$node2 = $h->appendChild($xml->createElement('node2'));
$node2->appendChild($xml->createTextNode('bbb'));
$xml->save("xml.xml");
?>
I'm relatively new to parsing XML files and am attempting to read a large XML file with XMLReader.
<?xml version="1.0" encoding="UTF-8"?>
<ShowVehicleRemarketing environment="Production" lang="en-CA" release="8.1-Lite" xsi:schemaLocation="http://www.starstandards.org/STAR /STAR/Rev4.2.4/BODs/Standalone/ShowVehicleRemarketing.xsd">
<ApplicationArea>
<Sender>
<Component>Component</Component>
<Task>Task</Task>
<ReferenceId>w5/cron</ReferenceId>
<CreatorNameCode>CreatorNameCode</CreatorNameCode>
<SenderNameCode>SenderNameCode</SenderNameCode>
<SenderURI>http://www.example.com</SenderURI>
<Language>en-CA</Language>
<ServiceId>ServiceId</ServiceId>
</Sender>
<CreationDateTime>CreationDateTime</CreationDateTime>
<Destination>
<DestinationNameCode>example</DestinationNameCode>
</Destination>
</ApplicationArea>
...
I am recieving the following error
ErrorException [ Warning ]: XMLReader::read() [xmlreader.read]: compress.zlib://D:/WebDev/example/local/public/../upload/example.xml.gz:2: namespace error : Namespace prefix xsi for schemaLocation on ShowVehicleRemarketing is not defined
I've searched around and can't find much useful information on using XMLReader to read XML files with namespaces -- How would I go about defining a namespace, if that is in fact what I need to do.. little help? links to pertinent resources?
There needs to be a definition of the xsi namespace. E.g.
<ShowVehicleRemarketing
environment="Production"
lang="en-CA"
release="8.1-Lite"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.starstandards.org/STAR/STAR/Rev4.2.4/BODs/Standalone/ShowVehicleRemarketing.xsd"
>
Update: You could write a user defined filter and then let the XMLReader use that filter, something like:
stream_filter_register('darn', 'DarnFilter');
$src = 'php://filter/read=darn/resource=compress.zlib://something.xml.gz';
$reader->open($src);
The contents read by the compress.zlib wrapper is then "routed" through the DarnFilter which has to find the (first) location where it can insert the xmlns:xsi declaration. But this is quite messy and will take some afford to do it right (e.g. theoretically bucket A could contain xs, bucket B i:schem and bucket C aLocation=")
Update 2: here's an ad-hoc example of a filter in php that inserts the xsi namespace declaration. Mostly untested (worked with the one test I ran ;-) ) and undocumented. Take it as a proof-of-concept not production-code.
<?php
stream_filter_register('darn', 'DarnFilter');
$src = 'php://filter/read=darn/resource=compress.zlib://d:/test.xml.gz';
$r = new XMLReader;
$r->open($src);
while($r->read()) {
echo '.';
}
class DarnFilter extends php_user_filter {
protected $buffer='';
protected $status = PSFS_FEED_ME;
public function filter($in, $out, &$consumed, $closing)
{
while ( $bucket = stream_bucket_make_writeable($in) ) {
$consumed += $bucket->datalen;
if ( PSFS_PASS_ON == $this->status ) {
// we're already done, just copy the content
stream_bucket_append($out, $bucket);
}
else {
$this->buffer .= $bucket->data;
if ( $this->foo() ) {
// first element found
// send the current buffer
$bucket->data = $this->buffer;
$bucket->datalen = strlen($bucket->data);
stream_bucket_append($out, $bucket);
$this->buffer = null;
// no need for further processing
$this->status = PSFS_PASS_ON;
}
}
}
return $this->status;
}
/* looks for the first (root) element in $this->buffer
* if it doesn't contain a xsi namespace decl inserts it
*/
protected function foo() {
$rc = false;
if ( preg_match('!<([^?>\s]+)\s?([^>]*)>!', $this->buffer, $m, PREG_OFFSET_CAPTURE) ) {
$rc = true;
if ( false===strpos($m[2][0], 'xmlns:xsi') ) {
echo ' inserting xsi decl ';
$in = '<'.$m[1][0]
. ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
. $m[2][0] . '>';
$this->buffer = substr($this->buffer, 0, $m[0][1])
. $in
. substr($this->buffer, $m[0][1] + strlen($m[0][0]));
}
}
return $rc;
}
}
Update 3: And here's an ad-hoc solution written in C#
XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
// prime the XMLReader with the xsi namespace
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
using ( XmlReader reader = XmlTextReader.Create(
new GZipStream(new FileStream(#"\test.xml.gz", FileMode.Open, FileAccess.Read), CompressionMode.Decompress),
new XmlReaderSettings(),
new XmlParserContext(null, nsmgr, null, XmlSpace.None)
)) {
while (reader.Read())
{
System.Console.Write('.');
}
}
You can file_get_contents and str_replace the XML before passing it to XMLReader.
Either insert the required namespace declararation for the xsi prefix:
$reader = new XMLReader;
$reader->xml(str_replace(
'<ShowVehicleRemarketing',
'<ShowVehicleRemarketing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"',
file_get_contents('http://example.com/data.xml')));
Another option would be to remove the schemaLocation attribute:
$reader->xml(str_replace(
'xsi:schemaLocation="http://www.starstandards.org/STAR /STAR/Rev4.2.4/BODs/Standalone/ShowVehicleRemarketing.xsd"',
'',
file_get_contents('http://example.com/data.xml')));
However, if there is more prefixes in the document, you will have to replace all of them.
Either fix whatever's writing out malformed XML, or write a separate tool to perform the fix later. (It doesn't have to read it all into memory at the same time, necessarily - stream the data in/out, perhaps reading and writing a line at a time.)
That way your reading code doesn't need to worry about trying to do something useful with the data and fixing it up at the same time.
The xsi namespace is normally reserved for use with Schema Instance Namespace:
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
if it isn't, your XML file is not XML+NS compliant and cannot be parsed. So you should solve that in the source document.
A note on xsi: it is even more vital than some possible other namespaces, because it directs a validating parser to the correct schema locations for the schema of your XML.
I'm working on a new class to wrap XML handling. I want my class to use simplexml if it's installed, and the built in XML functions if it's not. Can anyone give me some suggestions on a skeleton class to do this? It seems "wrong" to litter each method with a bunch of if statements, and that also seems like it would make it nearly impossible to correctly test.
Any upfront suggestions would be great!
EDIT: I'm talking about these built-in xml functions.
Which built-in xml functions are you referring to? SimpleXml is a standard extension, which uses libxml underneath - just as the dom extension does. So if the dom extension is installed, chances are that so is SimpleXml.
I've made a class which wraps SimpleXml functionality... take what you may from it...
bXml.class.inc
There is one weird thing... it's that SimpleXml doesn't allow its constructor to be overloaded, so you can't do things at initiation ... like override the input value (i.e. so you can accept XML as in input). I got around that limitation by using an ArrayObject class to wrap the new SimpleXml class.
I use something like this for doing xml translations and content:
Assuming xml structure something like this (important to use a regular structure, means you can pull off some nice agile tricks!):
<word name="nameofitem">
<en>value</en>
<pt>valor</pt>
<de>value_de</de>
</word>
and then a class to handle the xml:
class translations
{
public $xml = null;
private $file = null;
private $dom = null;
function __construct($file="translations") {
// get xml
$this->file = $file;
$this->haschanges = false;
$this->xml = file_get_contents($_SERVER['DOCUMENT_ROOT']."/xml/".$file.".xml");
$this->dom = new DOMdocument();
$this->dom->loadXML($this->xml);
}
function updateNode($toupdate, $newvalue, $lang="pt",$rootnode="word"){
$this->haschanges = true;
$nodes = $this->dom->getElementsByTagName($rootnode);
foreach ($nodes as $key => $value) {
if ($value->getAttribute("name")==$toupdate) {
$nodes->item($key)->getElementsByTagName($lang)->item(0)->nodeValue = htmlspecialchars($newvalue,ENT_QUOTES,'UTF-8');
}
}
}
function saveUpdated(){
$toSave = $this->dom->saveXML();
if ($this->haschanges === true) {
file_put_contents($_SERVER['DOCUMENT_ROOT']."/xml/".$this->file.".xml", $toSave);
return true;
}
else {
return false;
}
}
}
I took out a few of the methods I have, for brevity, but I extend this with things to handle file and image uploads etc too.
Once you have all this you can do:
$xml = new translations();
// loop through all the language posts
foreach ($_POST["xml"]["en"] as $key => $value) {
$xml->updateNode($key, stripslashes($value), "en");
}
Or something ;) hope this gives you some ideas!