How do i edit a xml files and add a new entry at end of < / user > ?
My xml(filezilla) look like
<FileZillaServer>
<Users>
<User Name="test">
</User>
/* using php to add another users on here <User Name="test2" */
</Users>
</FileZillaServer>
Thank you for help.
You can use the DOMDocument classes to manipulate an XML document.
For instance, you could use something like this :
$str = <<<XML
<FileZillaServer>
<Users>
<User Name="test">
</User>
</Users>
</FileZillaServer>
XML;
$xml = DOMDocument::loadXML($str);
$users = $xml->getElementsByTagName('Users');
$newUser = $xml->createElement('User');
$newUser->setAttribute('name', 'test2');
$users->item($users->length - 1)->appendChild($newUser);
var_dump($xml->saveXML());
Which will get you :
string '<?xml version="1.0"?>
<FileZillaServer>
<Users>
<User Name="test">
</User>
<User name="test2"/></Users>
</FileZillaServer>
' (length=147)
i.e. you :
create a new User element
you set its name attribute
and you append that new element to Users
(There are probably other ways to do that, avoiding the usage of length ; but this is what I first thought about -- quite early in the morning ^^ )
Use SimpleXML. As the name implies, it's the simplest way to deal with XML documents.
$FileZillaServer = simplexml_load_string(
'<FileZillaServer>
<Users>
<User Name="test" />
</Users>
</FileZillaServer>'
);
$User = $FileZillaServer->Users->addChild('User');
$User['Name'] = 'Test2';
echo $FileZillaServer->asXML();
Related
I am curious if I can search an XML file for a certain tag with regular expressions. I can search the file if I use fopen('foo.xml'); but it will only allow me to search the content between the tags not the tags them self. My objective for this is I hope to create a function that will allow me to delete all the content between two tags for example between users which are in a xml file. He language that I am using is PHP.
Thanks in advance john.
You should use something like SimpleXMLto handle/edit XML files.
If you really insist on doing it by treating the SML file as a string you can do something like this (or you can use regex). But you should use an XML library.
// get your file as a string
$yourXML = file_get_contents($file) ;
$posStart = stripos($yourXML,'<users>') + strlen('<users>') ;
$posEnd = stripos($yourXML,'</users>') ;
$newXML = substr($yourXML,0,$posStart) . substr($yourXML,$posEnd) ;
// <users> is now empty
echo $newXML ;
DomDocument & XPath will make things very clean, direct and reliable.
You can use evaluate() or query() as they provide the same result.
// will seek out the matching tags regardless of their location.
Be aware that my solution is case-sensitive.
Code: (Demo)
$xml = <<<XML
<myXml>
<Person>
<firstName>pradeep</firstName>
<lastName>jain</lastName>
<address>
<doorNumber>287</doorNumber>
<street>2nd block</street>
<city>bangalore</city>
</address>
<phoneNums type="mobile">9980572765</phoneNums>
<phoneNums type="landline">080 42056434</phoneNums>
<phoneNums type="skype">123456</phoneNums>
</Person>
<Person>
<firstName>pradeep</firstName>
<lastName>jain</lastName>
<address>
<doorNumber>287</doorNumber>
<street>2nd block</street>
<city>bangalore</city>
</address>
<phoneNums type="mobile">1</phoneNums>
<phoneNums type="landline">2</phoneNums>
<phoneNums type="skype">3</phoneNums>
</Person>
</myXml>
XML;
$dom = new DOMDocument;
$dom->loadXML($xml); // <-- you'll need to import your file instead of a string as demo'ed here
$xpath = new DOMXPath($dom);
echo count($xpath->evaluate("//phoneNums")) , "\n"; // 6
echo count($xpath->evaluate("//street")) , "\n"; // 2
echo count($xpath->evaluate("//myXml")) , "\n"; // 1
echo count($xpath->evaluate("//Person")) , "\n"; // 2
echo count($xpath->evaluate("//person")) , "\n"; // 0 <-- case-sensitive
As a simple mock up of the various parts needed to do this in SimpleXML, there are a few concepts you need to know to get it to work.
The main one being XPath, which a sort of SQL for XML. Of course it has it's own notation and can be a little pedantic at times, but you can experiment with it on sites like https://codebeautify.org/Xpath-Tester.
$data = '<?xml version="1.0" encoding="UTF-8"?>
<Users>
<User id="123">
<Name>fred</Name>
<Extension>1234</Extension>
</User>
<User id="124">
<Name>bert</Name>
<Extension>1235</Extension>
</User>
<User id="125">
<Name>foo</Name>
<Extension>1236</Extension>
</User>
</Users>';
$userID = "123";
$users = simplexml_load_string($data);
// Find the user with the id attribute (use [0] as the call to xpath
// returns a list of matches and you only want the first one)
$userMatch = $users->xpath("//User[#id='{$userID}']")[0];
// Just output user id attribute and name
echo "id=".$userMatch['id'].",name=".$userMatch->Name.PHP_EOL;
echo "Removing user...".PHP_EOL;
// Remove the user - note the [0] is required here
unset($userMatch[0]);
// Print out the resulting XML after the removal
echo $users->asXML();
I've put comments through the code as how it works. The output is...
id=123,name=fred
Removing user...
<?xml version="1.0" encoding="UTF-8"?>
<Users>
<User id="124">
<Name>bert</Name>
<Extension>1235</Extension>
</User>
<User id="125">
<Name>foo</Name>
<Extension>1236</Extension>
</User>
</Users>
I am beginner in php and currently working on php-xml parsing in which i am not getting how should i append node with specific node having different value in same xml file.
Explanation :
Since i don't have enough data so i need to duplicate nodes (here it is test node) so that i can increase my file size and then work on parsing.
In short i need to generate big xml file with exisitng single node.
Current Xml File :
<?xml version="1.0" encoding="utf-8"?>
<Testings xmlns="http://rets.org/xsd/Syndication/2012-03" xmlns:Level="http://rets.org/xsd/RETSLevel" xmlns:schemaLocation="http://rets.org/xsd/Syndication/2012-03/Syndication.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="0.96" versionTimestamp="2012-02-07T03:00:00Z" xml:lang="en-us">
<Test>
<Area>
<Level:preference-order>1</Level:preference-order>
<Level:address-preference-order>1</Level:address-preference-order>
<Level:FullStreetAddress>2245 Don Knotts Blvd.</Level:FullStreetAddress>
<Level:UnitNumber>2</Level:UnitNumber>
<Level:City>Morgantown</Level:City>
<Level:StateOrProvince>WV</Level:StateOrProvince>
<Level:PostalCode>26501</Level:PostalCode>
<Level:Country>true</Level:Country>
</Area>
<AreaPrice Level:isgSecurityClass="Public">234000</ListPrice>
<AreaPriceLow Level:isgSecurityClass="Public">214000</ListPriceLow>
<AreaPrices>
<AreaPrice>
<AreaListPrice Level:currencyCode="AUS" Level:isgSecurityClass="Public">483999.0</AreaListPrice>
<AreaListPriceLow Level:currencyCode="EUR" Level:isgSecurityClass="Public">470000.0</AreaListPriceLow>
</AreaPrice>
</AreaPrices>
</Test>
</Testings>
Expected Output:
<?xml version="1.0" encoding="utf-8"?>
<Testings xmlns="http://rets.org/xsd/Syndication/2012-03" xmlns:Level="http://rets.org/xsd/RETSLevel" xmlns:schemaLocation="http://rets.org/xsd/Syndication/2012-03/Syndication.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="0.96" versionTimestamp="2012-02-07T03:00:00Z" xml:lang="en-us">
<Test>
<Area>
<Level:preference-order>1</Level:preference-order>
<Level:address-preference-order>1</Level:address-preference-order>
<Level:FullStreetAddress>2245 Don Knotts Blvd.</Level:FullStreetAddress>
<Level:UnitNumber>2</Level:UnitNumber>
<Level:City>Morgantown</Level:City>
<Level:StateOrProvince>WV</Level:StateOrProvince>
<Level:PostalCode>26501</Level:PostalCode>
<Level:Country>true</Level:Country>
</Area>
<AreaPrice Level:isgSecurityClass="Public">234000</ListPrice>
<AreaPriceLow Level:isgSecurityClass="Public">214000</ListPriceLow>
<AreaPrices>
<AreaPrice>
<AreaListPrice Level:currencyCode="AUS" Level:isgSecurityClass="Public">483999.0</AreaListPrice>
<AreaListPriceLow Level:currencyCode="EUR" Level:isgSecurityClass="Public">470000.0</AreaListPriceLow>
</AreaPrice>
</AreaPrices>
</Test>
<Test>
<Area>
<Level:preference-order>1</Level:preference-order>
<Level:address-preference-order>1</Level:address-preference-order>
<Level:FullStreetAddress>2245 Don Knotts Blvd.</Level:FullStreetAddress>
<Level:UnitNumber>2</Level:UnitNumber>
<Level:City>Morgantown</Level:City>
<Level:StateOrProvince>WV</Level:StateOrProvince>
<Level:PostalCode>26501</Level:PostalCode>
<Level:Country>true</Level:Country>
</Area>
<AreaPrice Level:isgSecurityClass="Public">15000</ListPrice>
<AreaPriceLow Level:isgSecurityClass="Public">214000</ListPriceLow>
<AreaPrices>
<AreaPrice>
<AreaListPrice Level:currencyCode="AUS" Level:isgSecurityClass="Public">483999.0</AreaListPrice>
<AreaListPriceLow Level:currencyCode="EUR" Level:isgSecurityClass="Public">470000.0</AreaListPriceLow>
</AreaPrice>
</AreaPrices>
</Test>
</Testings>
**My Approach **
$xmlString = simplexml_load_string(file_get_contents('./PhpXmlFile.xml'));
$xmlString = $xmlString->xpath('/Testings/Test/');
if ( $xmlString && is_array( $xmlString ) ) {
// since it IS an array, set to the first element of the array
$xmlString = $xmlString[0];
// And NOW we can append
$xmlString = $xmlString->addChild('Test','');
}
$dom = new DOMDocument("1.0");
$dom->preserveWhiteSpace = true;
$dom->formatOutput = true;
$dom->loadXML($xmlString->saveXML());
Thanks in advance!!
Here we are using DOMDocument for cloning a child node. Here for an example i am using nodeValue as 1000 you can change it to the value you want.
Here in a below code we are using $domDocument->getElementsByTagName("AreaPrice")->item(2)->nodeValue=1000; for item no 2 because after appending the a clone node, There will be four elements with name AreaPrice.
Try this code snippet here
<?php
ini_set('display_errors', 1);
$string = <<<HTML
<?xml version="1.0" encoding="utf-8"?>
<Testings xmlns="http://rets.org/xsd/Syndication/2012-03" xmlns:Level="http://rets.org/xsd/RETSLevel" xmlns:schemaLocation="http://rets.org/xsd/Syndication/2012-03/Syndication.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="0.96" versionTimestamp="2012-02-07T03:00:00Z" xml:lang="en-us">
<Test>
<Area>
<Level:preference-order class='sas'>1</Level:preference-order>
<Level:address-preference-order>1</Level:address-preference-order>
<Level:FullStreetAddress>2245 Don Knotts Blvd.</Level:FullStreetAddress>
<Level:UnitNumber>2</Level:UnitNumber>
<Level:City>Morgantown</Level:City>
<Level:StateOrProvince>WV</Level:StateOrProvince>
<Level:PostalCode>26501</Level:PostalCode>
<Level:Country>true</Level:Country>
</Area>
<AreaPrice Level:isgSecurityClass="Public">234000</AreaPrice>
<AreaPriceLow Level:isgSecurityClass="Public">214000</AreaPriceLow>
<AreaPrices>
<AreaPrice>
<AreaListPrice Level:currencyCode="AUS" Level:isgSecurityClass="Public">483999.0</AreaListPrice>
<AreaListPriceLow Level:currencyCode="EUR" Level:isgSecurityClass="Public">470000.0</AreaListPriceLow>
</AreaPrice>
</AreaPrices>
</Test>
</Testings>
HTML;
$domDocument = new DOMDocument();
$domDocument->loadXML($string);
$results=$domDocument->getElementsByTagName("Test");
$clonedNode=$results->item(0)->cloneNode(true);
$results->item(0)->parentNode->appendChild($clonedNode);
$domDocument->getElementsByTagName("AreaPrice")->item(2)->nodeValue=1000;//change the value you want.
echo $domDocument->saveXML();
I'd like to get the content of the attribute xsi:schemaLocation. It's works perfectly with getElementsByTagName in php (and foreach after) but it's ugly, right ?
How to get the same content with a simple Xpath query ?
Here a short example of the xml content :
<?xml version="1.0" encoding="utf-8"?>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="1.0" creator="blabla" xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/cache.xsd" xmlns="http://www.topografix.com/GPX/1/0">
...
</gpx>
Thanks!
Typically you need to register the namespaces you want to use with the XPath library first. Then you can query the attribute by including namespace prefix along with the name.
So let's assume you're using DOMXPath, you might register the following namespaces:
$xpath = new DOMXPath($doc);
$xpath->registerNamespace("xsi","http://www.w3.org/2001/XMLSchema-instance");
$xpath->registerNamespace("gpx", "http://www.topografix.com/GPX/1/0");
And then you can query the schemaLocation attribute with something like this:
$xpath->query("/gpx:gpx/#xsi:schemaLocation",$doc);
Using the SimpleXMLElement class you can easily get the attribute xsi:schemaLocation's value:
<?php
$xml = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="1.0" creator="blabla" xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/cache.xsd" xmlns="http://www.topografix.com/GPX/1/0">
</gpx>
XML;
$sxe = new SimpleXMLElement($xml);
$schemaLocation = $sxe->attributes('xsi', true)->schemaLocation;
echo (string) $schemaLocation;
I want to add a child for a cetrain user.
$file = simplexml_load_file('gebruikers.xml');
$user = $file->$_SESSION["S_voornaam"];
$usercord = $user->addChild('coordinaat');
$usercord->addChild('1',$_SESSION["S_coordinaat"]);
file_put_contents('gebruikers.xml', $file->asXML());
This is my xml file.
<?xml version="1.0"?>
<gebruikers>
<user>
<voornaam>admin</voornaam>
<achternaam>web</achternaam>
<wachtwoord>1234</wachtwoord>
</user>
<user>
<voornaam>jef</voornaam>
<achternaam>gys</achternaam>
<wachtwoord>1234</wachtwoord>
</user>
</gebruikers>
Example:
When the $_SESSION["S_voornaam"] = admin
and $_SESSION["S_coordinaat"] = (51.2241558, 4.41293399999995)
This is the result i want.
<?xml version="1.0"?>
<gebruikers>
<user>
<voornaam>admin</voornaam>
<achternaam>web</achternaam>
<wachtwoord>1234</wachtwoord>
<coordinaat>
<1>(51.2241558, 4.41293399999995)</1>
</coordinaat>
</user>
<user>
<voornaam>jef</voornaam>
<achternaam>gys</achternaam>
<wachtwoord>1234</wachtwoord>
</user>
</gebruikers>
Example;
$user = $file->xpath('//user[voornaam = "name"]')[0];
I need to restructure a very large xml source, example is at
http://www.fluffyduck.com.au/sampleXML.xml
I need to modify it for jstree however I'm not sure how to manipulate the data recursively, as loading it as xml with simpleXml only see's the first 1 user record.
<user id="41" username="bsmain" firstname="Boss" lastname="MyTest" fullname="Test Name" email="lalal#test.com" logins="1964" lastseen="11/09/2012">
</user>
to
<user id="41">
<content><name>bsmain</name></content>
</user>
The problem is some xml lines do not have a closing tag such as , but instead look like this :
<user id="61" username="underling" firstname="Under" lastname="MyTest" fullname="Test Name" email="lalal#test.com" logins="4" lastseen="08/09/2009"/>
If i modify this record and add underling jstree does not recognise it, i'm presuming the /> at the end is the same as ?
I did want to do this in XML but am thinking it may be easier, to simply somehow parse the xml file 'line by line', read in the line of data explode it perhaps,
then create a new variable storing it with modified contents such as :
<user id="61">
<content><name>bsmain</name>
</user>
and on the rows where /> exists at the end, manually insert a tag.
there has to be a smarter/faster way to achieve this.
Your best bet is to use DOMDocument for XML parsing. I have written an example that transforms attributes (excluding the id attribute) to content elements:
Code
<?php
$s =
'<users>' .
'<user id="61" username="underling" firstname="Under" lastname="MyTest" fullname="Test Name" email="lalal#test.com" logins="4" lastseen="08/09/2009"/>' .
'<user id="61" username="underling" firstname="Under" lastname="MyTest" fullname="Test Name" email="lalal#test.com" logins="4" lastseen="08/09/2009"/>' .
'<user id="8" test="testvalue"></user>' .
'</users>';
$doc = new DOMDocument();
$doc->loadXML($s);
$users = $doc->getElementsByTagName("user");
foreach ($users as $user)
{
if ($user->hasAttributes())
{
// create content node
$content = $user->appendChild($doc->createElement("content"));
// transform attributes into content elements
for ($i = 0; $i < $user->attributes->length; $i++)
{
$attr = $user->attributes->item($i);
if (strtolower($attr->name) != "id")
{
if ($user->removeAttribute($attr->name))
{
$content->appendChild($doc->createElement($attr->name, $attr->value));
$i--;
}
}
}
}
}
header("Content-Type: text/xml");
echo $doc->saveXML();
?>
Output
<users>
<user id="61">
<content>
<username>underling</username>
<firstname>Under</firstname>
<lastname>MyTest</lastname>
<fullname>Test Name</fullname>
<email>lalal#test.com</email>
<logins>4</logins>
<lastseen>08/09/2009</lastseen>
</content>
</user>
<user id="61">
<content>
<username>underling</username>
<firstname>Under</firstname>
<lastname>MyTest</lastname>
<fullname>Test Name</fullname>
<email>lalal#test.com</email>
<logins>4</logins>
<lastseen>08/09/2009</lastseen>
</content>
</user>
<user id="8">
<content>
<test>testvalue</test>
</content>
</user>
</users>