PHP DOM XML - Create Multiple Namespace Attributes? - php

I'm working on some PHP to create XML from a database using the DOM extension.
Basically, I need to create a NameSpace and add 3 attributes to it:
<NameSpaceName xmlns="uri:xxx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="uri:xxx">
The full code i've written is below:
include_once("includes/connect.php");
$sql = ("SELECT * FROM tableName");
$query = mysql_query($sql) or die("Error: " . mysql_error());
// create a new XML document
$doc = new DomDocument('1.0', 'UTF-8');
// create root node
$root = $doc->createElementNS('uri:xxx', 'PayerRecords');
$root = $doc->appendChild($root);
$root->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$root->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xsi:schemaLocation', 'uri:xxx');
// process one row at a time
while($row = mysql_fetch_assoc($query)) {
// add node for each row
$occ = $doc->createElement('Content');
$occ = $root->appendChild($occ);
// add a child node for each field
foreach ($row as $fieldname => $fieldvalue) {
$child = $doc->createElement($fieldname);
$child = $occ->appendChild($child);
$value = $doc->createTextNode($fieldvalue);
$value = $child->appendChild($value);
} // foreach
} // while
// get completed xml document
$xml_string = $doc->saveXML();
echo $xml_string;
But when I execute the above I get this error:
Fatal error: Uncaught exception
'DOMException' with message 'Namespace
Error' in
xml.php:21
Stack trace: #0
xml.php(21):
DOMElement->setAttributeNS('http://www.w3.o...', 'xsi:schemaLocat...',
'uri:xxx...') #1 {main} thrown
in
xml.php
on line 21
Line 21 is the second 'setAttributeNS' line.
Can anyone see where i'm going wrong?

schemaLocation is not declared in the namespace http://www.w3.org/2000/xmlns/ but in http://www.w3.org/2001/XMLSchema-instance
<?php
// create a new XML document
$doc = new DomDocument('1.0', 'UTF-8');
// create root node
$root = $doc->createElementNS('http://xxx', 'PayerRecords');
$root = $doc->appendChild($root);
$root->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$root->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation', 'http://xxx');
echo $doc->savexml();
prints
<?xml version="1.0" encoding="UTF-8"?>
<PayerRecords xmlns="http://xxx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xxx"/>

I didn't quite get it the first time so I'm posting my answer in more detail. Maybe someone finds this helpful.
// create DOM document
$xml = new DomDocument('1.0', 'UTF-8');
// create root element
$el = $xml->createElementNS('http://namespaceA/url/here/', 'rootelement');
// to be able to add new namespaces we must first add namespace 'xsi'
// third parameter is important (use your main namespace with .xsd)
$root->setAttributeNS(
'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation',
'http://namespaceA/url/here/ http://namespaceA/xsdfile/here.xsd');
// add new namespace
$el->setAttributeNS(
'http://www.w3.org/2000/xmlns/',
'xmlns:namespaceB',
'http://namespaceB/url/here/');
// add root element to DOM
$xml->appendChild($el);
This mail archive message was very helpful: http://www.mail-archive.com/php-general#lists.php.net/msg135362.html.

replace line 21 with
$root->setAttributeNS(
'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation',
'http://xxx http://xxx/xxx.xsd'
);
xsi:schemaLocation is not defined in the http://www.w3.org/2000/xmlns/ or your namespace, but in xsi. so you have to use the (complete) xsi namespace uri as the first parameter.
and: you don't need to call setAttributeNS() twice: the single line above generates both the xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" and xsi:schemaLocation="http://xxx http://xxx/xxx.xsd" attributes.

Related

How to add a child in xml without overwrite using php dom?

I have wrote this code in PHP to compile an XML file with parameters that are in URL.
But when the XML file is already created instead of adding the new data at the bottom of file inside the root element, overwrite it and delete all old data.
Where is the problem?
I have seen some examples online but I can't figure out how fix it.
I need to verify if file already exist and then add the element?
Or I need to read it and then add again the old elements and new?
I don't know very well dom so I can't figure out
<?php
$FOL = $_GET["FOL"];
$NUM = $_GET["NUM"];
$DAT = $_GET["DAT"];
$ZON = $_GET["ZON"];
$TIP = $_GET["TIP"];
$COM = $_GET["COM"];
$dom = new DOMDocument();
$dom->encoding = 'utf-8';
$dom->xmlVersion = '1.0';
$dom->formatOutput = true;
$xml_file_name = "$NUM.xml";
$xmlString = file_get_contents($xml_file_name);
$dom->loadXML($xmlString);
$loaded_xml = $dom->getElementsByTagName('Territorio');
$territorio_node = $dom->createElement('Territorio');
$child_node_NOM = $dom->createElement('NOM', "$NOM");
$territorio_node->appendChild($child_node_NOM);
$child_node_NUM = $dom->createElement('NUM', "$NUM");
$territorio_node->appendChild($child_node_NUM);
$child_node_DAT = $dom->createElement('DAT', "$DAT");
$territorio_node->appendChild($child_node_DAT);
$child_node_ZON = $dom->createElement('ZON', "$ZON");
$territorio_node->appendChild($child_node_ZON);
$dom->appendChild($territorio_node);
$child_node_TIP = $dom->createElement('TIP', "$TIP");
$territorio_node->appendChild($child_node_TIP);
$child_node_COM = $dom->createElement('COM', "$COM");
$territorio_node->appendChild($child_node_COM);
$dom->appendChild($territorio_node);
$dom->save($FOL.'/'.$xml_file_name);
echo "$xml_file_name creato correttamente";
?>
as per the comment: You should check that the root node of the XML file exists before calling createElement to generate a new one. To do that you can call getElementsByClassName and test whether the first entry is empty
ie: empty( $dom->getElementsByTagName('Territorio')[0] ) sort of thing...
If the root node exists we use that, otherwise add a new root to the document and continue
// check that the querystring has all the required parameters
if( isset(
$_GET['FOL'],
$_GET['NUM'],
$_GET['DAT'],
$_GET['ZON'],
$_GET['TIP'],
$_GET['COM']
)){
// the filename is generated from one of the querystring parameters
// - here the directory used is the same as the script running
$file=sprintf( '%s/%s.xml', __DIR__, $_GET['NUM'] );
// create an empty file if it does not exist
if( !file_exists( $file )){
file_put_contents( $file, '' );
}
clearstatcache();
// create the DOMDocument and set various options
libxml_use_internal_errors( true );
$dom=new DOMDocument('1.0','utf-8');
$dom->strictErrorChecking=false;
$dom->preserveWhiteSpace=true;
$dom->formatOutput=true;
$dom->recover=true;
// load the XML file directly rather than loading a string read from the original file.
$dom->load( $file );
// The ROOT node of the document ... does it exist? if not, create it and add to the DOM.
$root=$dom->getElementsByTagName('Territorio')[0];
if( empty( $root ) ){
$root=$dom->createElement('Territorio');
$dom->appendChild( $root );
}
// I added this part so that you can distinguish easily new elements
$record=$dom->createElement('record');
$root->appendChild( $record );
// add all the querystring parameters within the new record.
$record->appendChild( $dom->createElement('NUM', $_GET["NUM"] ) );
$record->appendChild( $dom->createElement('DAT', $_GET["DAT"] ) );
$record->appendChild( $dom->createElement('ZON', $_GET["ZON"] ) );
$record->appendChild( $dom->createElement('TIP', $_GET["TIP"] ) );
$record->appendChild( $dom->createElement('COM', $_GET["COM"] ) );
$record->appendChild( $dom->createElement('FOL', $_GET["FOL"] ) );
$dom->save( $file );
}
An example of the XML generated:
<?xml version="1.0" encoding="utf-8"?>
<Territorio>
<record>
<NUM>wibble</NUM>
<DAT>25/10/2022</DAT>
<ZON>europe</ZON>
<TIP>total</TIP>
<COM>94</COM>
<FOL>234</FOL>
</record>
<record>
<NUM>wibble</NUM>
<DAT>26/10/2022</DAT>
<ZON>europe</ZON>
<TIP>total</TIP>
<COM>96</COM>
<FOL>238</FOL>
</record>
</Territorio>
In the original code the file is saved to a location defined by another parameter in the querystring ( only just noticed that afterwards ) so rather than
$file=sprintf( '%s/%s.xml', __DIR__, $_GET['NUM'] );
you would likely want to do:
$file=sprintf( '%s/%s.xml', $_GET['FOL'], $_GET['NUM'] );
The root node of an XML document is called document element and here is an property for it. So you can just check if it is undefined. However an document can have only a single document element, so will need to modify the structure of your XML - for example add a "Territori" document element.
Do not use the second argument of the createElement() method or the $nodeValue property. Their escaping is broken - try adding a value with an &. Use $textContent or add a text node.
In modern DOM you can even just append() a string.
$NUM = "NUM";
$DAT = "DAT";
$ZON = "ZON";
$document = new DOMDocument('1.0', 'UTF-8');
// let the parser ignore existing indents
$document->preserveWhiteSpace = false;
$document->loadXML(getXMLString());
// fetch or create document element
$territori = $document->documentElement
?? $document->appendChild($document->createElement('Territori'));
// create/append an item element
$territori
->appendChild(
$territorio = $document->createElement('Territorio')
);
// create/append an element and set its text content
$territorio
->appendChild($document->createElement('NUM'))
->textContent = $NUM;
// create/append an element with a text child node
$territorio
->appendChild($document->createElement('DAT'))
->appendChild($document->createTextNode($DAT));
// create/append an element and a string (DOM Level 3)
$territorio
->appendChild($document->createElement('ZON'))
->append((string)$ZON);
// enable output formatting
$document->formatOutput = true;
echo $document->saveXML();
function getXMLString() {
return <<<'XML'
<?xml version="1.0"?>
<Territori>
<Territorio>
<NUM>NUM</NUM>
<DAT>DAT</DAT>
<ZON>DAT</ZON>
</Territorio>
</Territori>
XML;
}
For a more flexible approach to fetch nodes use Xpath expressions. Here is an example that checks if an Territorio with a specific NUM value exists:
$document = new DOMDocument('1.0', 'UTF-8');
$document->loadXML(getXMLString());
$xpath = new DOMXpath($document);
if ($xpath->evaluate('count(//Territorio[NUM="NUM"]) > 0')) {
echo "Node exists";
}

Php:Proble when i convert in xml

I want my arElemt(gurl and gname) put in . Example and problem2 = when i write g:url or g:name = Error... php7.2* and now example now now i have this construction
-rss
---title
---link
---description
---gurl
---gname
i want now i have this construction
-rss
---title
---link
---description
---gurl
---gname
---gurl
---gname
---gurl
---gname i want
-rss
---title
---link
---description
---item
-----gurl
-----gname
---item
-----gurl
-----gname
---item
-----gurl
-----gname
---item
-----gurl
-----gname
header("Content-type: text/xml; charset=utf-8");
$dom = new DOMDocument('1.0','utf-8');
$root = $dom->createElement('rss');
$dom->appendChild($root);
$title = $dom->createElement('title', 'test');
$root->appendChild($title );
$link = $dom->createElement('link', 'test');
$root->appendChild($link );
$description = $dom->createElement('description', 'test');
$root->appendChild($description );
$root = $item->createElement('item');
while($arElement = $rsElements->GetNext())
{
$url = $dom->createElement("gurl", $surl.$arElement[DETAIL_PAGE_URL]);
$item->appendChild($url );
$name = $dom->createElement("gname", $arElement[NAME]);
$root->appendChild($name );
}
echo $dom->saveXML();
$dom->save($file_name); // save as file
Here is a big difference between gurl and g:url. gurl is not an valid RSS tag afaik. g:url is an url element inside a defined namespace.
The g from g:url is a namespace prefix. It references a namespace definition. Look for a xmlns:g attribute in examples or for the namespace URI in the documentation of the format. The g is an alias for the value of that attribute. A parser resolves that to the URI internally. All the following nodes can be read as {urn:example:namespace}url.
<g:url xmlns:g="urn:example:namespace"/>
<g2:url xmlns:g2="urn:example:namespace"/>
<url xmlns="urn:example:namespace"/>
RSS itself is just wellformed XML, it uses no namespace. But it can contain other XML formats that use namespaces (MediaRSS, ...).
To create an element with a namespace use the method DOMDocument::createElementNS(). This will automatically add the namespace definition if needed. However if do not use the namespace for the document element it will be added multiple times. You can set the namespace definition as an attribute of the reserved XMLNS namespace.
$data = ['one', 'two'];
// the namespace for namespace definitions
const XMLNS_XMLNS = 'http://www.w3.org/2000/xmlns/';
// namespace referenced by prefix g?
const XMLNS_G = 'urn:example:namespace';
$document = new DOMDocument('1.0','utf-8');
$rss = $document->appendChild(
$document->createElement('rss')
);
// add the namespace definition to the document element
$rss->setAttributeNS(XMLNS_XMLNS, 'xmlns:g', XMLNS_G);
// create + append element node, set its text content
$rss->appendChild(
$document->createElement('title')
)->textContent = 'test';
foreach ($data as $value) {
$item = $rss->appendChild(
$document->createElement('item')
);
// create and append an element with the namespace
$item->appendChild(
$document->createElementNS(XMLNS_G, 'g:url')
)->textContent = 'http://example.com/page?'.$value;
}
$document->formatOutput = TRUE;
echo $document->saveXML();
Output:
<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:g="urn:example:namespace">
<title>test</title>
<item>
<g:url>http://example.com/page?one</g:url>
</item>
<item>
<g:url>http://example.com/page?two</g:url>
</item>
</rss>
Hint 1: DOMNode::appendChild() returns the appended node. It is possible to nest the create call.
Hint 2: DOMNode::$textContent allows to read/write the text content of a node and escapes properly.
const XMLNS_XMLNS = 'http://www.w3.org/2000/xmlns/';
// namespace referenced by prefix g?
const XMLNS_G = 'urn:example:namespace';
$document = new DOMDocument('1.0','utf-8');
$rss = $document->appendChild(
$document->createElement('rss')
);
// add the namespace definition to the document element
$rss->setAttributeNS(XMLNS_XMLNS, 'xmlns:g', XMLNS_G);
// create + append element node, set its text content
$rss->appendChild(
$document->createElement('title')
)->textContent = 'test';
while($arElement = $rsElements->GetNext())
{
$item = $rss->appendChild(
$document->createElement('item')
);
$item->appendChild(
$document->createElementNS(XMLNS_G, 'g:url')
)->textContent = $surl.$arElement["DETAIL_PAGE_URL"];
$item->appendChild(
$document->createElementNS(XMLNS_G, 'g:name')
)->textContent = $arElement["NAME"];
}

Add namespace attribute to xml node in php

Following is the node I am trying to create in my XML -
<?xml version="1.0" standalone="no" ?>
<manifest identifier="com.scorm.golfsamples.contentpackaging.multioscosinglefile.20043rd"
version="1"
xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_v1p3"
xmlns:adlseq="http://www.adlnet.org/xsd/adlseq_v1p3"
xmlns:adlnav="http://www.adlnet.org/xsd/adlnav_v1p3"
xmlns:imsss="http://www.imsglobal.org/xsd/imsss"
xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 imscp_v1p1.xsd
http://www.adlnet.org/xsd/adlcp_v1p3 adlcp_v1p3.xsd
http://www.adlnet.org/xsd/adlseq_v1p3 adlseq_v1p3.xsd
http://www.adlnet.org/xsd/adlnav_v1p3 adlnav_v1p3.xsd
http://www.imsglobal.org/xsd/imsss imsss_v1p0.xsd">
Code is working fine for identifier and version attribute but unable to generate it with namespace like xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
Tried this code from here but unable to make it :(
$doc = new DOMDocument( '1.0' );
$doc->loadXML( $source );
// (1) We just create a "namespace'd" attribute without appending it to any element.
$attr_ns = $doc->createAttributeNS( '{namespace_uri_here}', 'example:attr' );
print $doc->saveXML() . "\n";
Codepad Link - http://codepad.org/uLJc4hpP
Full code -
//creating an XML document
$dom = new DOMDocument('1.0');
$dom->xmlStandalone = false;
//create element manifest
$manfiestNode = $dom->createElement('manifest',"");
//create attribute identifier
$manfiestNodeAttr = $dom->createAttribute('identifier');
//value for the manifest node identifier value
$date = new DateTime();
$manfiestNodeAttr->value = 'course_'.date_format($date,'U');
//append attribute to the manifest element
$manfiestNode->appendChild($manfiestNodeAttr);
//create attribute with an associated namespace
$nodeAttr = $manfiestNode->createAttributeNS('{namespace_uri_here}', 'example:attr');
//append namespace to the manifest element
$nodeAttr->appendChild($manfiestNode);
//append manifest element to the document
$dom->appendChild($manfiestNode);
var_dump($dom->saveXML());
Let me know what I am conceptually doing wrong and how could I make it working.
I tried by changing $manfiestNode to $dom in line 20[codepad link] but still no luck :(.
Error-
Fatal error: Call to undefined method DOMElement::createAttributeNS()
on line 20
Try with createAttribute like following
$dom = new DOMDocument('1.0','UTF-8');
// root manifest
$root = $dom->appendChild($dom->createElement('manifest'));
// identifier
$date = new DateTime();
$manfiestNodeAttr_value = 'course_'.date_format($date,'U');
$root->appendChild($dom->createAttribute('identifier'))->appendChild($dom->createTextNode($manfiestNodeAttr_value));
// version
$version = 1;
$root->appendChild($dom->createAttribute('version'))->appendChild($dom->createTextNode($version));
// xmlns:xsi
$root->appendChild($dom->createAttribute('xmlns:xsi'))->appendChild($dom->createTextNode("http://www.w3.org/2001/XMLSchema-instance"));
print_r($dom->saveXML());
Demo Codepad: http://codepad.org/zgug0Gl3

How to create a valid XML tree root element in using only PHP?

How to create a valid XML tree using only PHP?
I have been running into many troubles with creating an XML tree just using PHP. I already have some code to show where I am at right now:
$xml = new DOMDocument("1.0");
$verb = $xml->createElement ('verb');
$vtext = $xml->createTextNode($_POST['verb']);
$verb->appendChild($vtext);
$xml->appendChild ($verb);
$adverb = $xml->createElement ('adverb');
$advtext = $xml->createTextNode($_POST['adverb']);
$adverb->appendChild($advtext);
$xml->appendChild ($adverb);
$xml ->save("'".$_POST[verb]."'.xml") or die ("error creating file");
So, with this and the user input, it creates a file that is whatever the verb is. The only thing is, I keep getting error messages that there is extra content below the verbs.
I know that this is because I'm not adding a root element, but how exactly would you add this root element without creating errors? There are very little forums even talking about PHP and XML alone, so it's hard to find one that's about making an XML tree.
How about something like this?
$xml = new DOMDocument("1.0");
$root = $xml->createElement ('root');
$xml->appendChild($root);
$verb = $xml->createElement ('verb');
$vtext = $xml->createTextNode($_POST['verb']);
$verb->appendChild($vtext);
$root->appendChild ($verb);
$adverb = $xml->createElement ('adverb');
$advtext = $xml->createTextNode($_POST['adverb']);
$adverb->appendChild($advtext);
$root->appendChild ($adverb);
$xml ->save("'".$_POST[verb]."'.xml") or die ("error creating file");
This is a sample i have found in stackoverflow and this work for me! hope this will also help you!
<?php
/* create a dom document with encoding utf8 */
$domtree = new DOMDocument('1.0', 'UTF-8');
/* create the root element of the xml tree */
$xmlRoot = $domtree->createElement("xml");
/* append it to the document created */
$xmlRoot = $domtree->appendChild($xmlRoot);
$currentTrack = $domtree->createElement("track");
$currentTrack = $xmlRoot->appendChild($currentTrack);
/* you should enclose the following two lines in a cicle */
$currentTrack->appendChild($domtree->createElement('path','song1.mp3'));
$currentTrack->appendChild($domtree->createElement('title','title of song1.mp3'));
$currentTrack->appendChild($domtree->createElement('path','song2.mp3'));
$currentTrack->appendChild($domtree->createElement('title','title of song2.mp3'));
/* get the xml printed */
echo $domtree->saveXML();
?>
How exactly would you add this root element without creating errors?
For a DOMDocument (in general, not only for the PHP extension), the documentElement (often also called root element) is technically a child-node of the DOMDocument object.
You create it by appending it (as you already do (!)):
$xml = new DOMDocument("1.0");
$root = $xml->createElement ('root');
$xml->appendChild($root);
The new documentElement now is available as:
$xml->documentElement;
Try it your own (online Demo):
$xml = new DOMDocument("1.0");
$xml->save('php://output'); // document is empty
The output is just the XML declaration, no root element:
Then adding the root element (here named root):
$root = $xml->createElement ('root');
$xml->appendChild($root);
$xml->save('php://output'); // document has root-node now
And the Document has a Root-Node now as the output shows:
<?xml version="1.0"?>
<root/>
The $root is the documentElement now and Children can be appended to it:
$root->appendChild($xml->createTextNode("\n "));
$root->appendChild($xml->createElement('hello', 'world'));
$root->appendChild($xml->createTextNode("\n "));
$root->appendChild($xml->createElement('answer', '42'));
$root->appendChild($xml->createTextNode("\n "));
$root->appendChild($xml->createElement('danger', 'danger'));
$root->appendChild($xml->createTextNode("\n"));
$xml->save('php://output');
The output then is:
<?xml version="1.0"?>
<root>
<hello>world</hello>
<answer>42</answer>
<danger>danger</danger>
</root>

about php 5.x create xml by dom document

I'm using DOMDocument class of PHP to create a xml file, my code is:
$xmlObject = new DOMDocument('1.0', 'utf-8');
//root node -- books
$books = $xmlObject->createElement('books');
//book node
$book = $xmlObject->createElement('book');
//book node's attribute -- index
$index = new DOMAttr('index', '1');
$book->appendChild($index);
//name node
$name = $xmlObject->createElement('name', 'Maozedong');
//name node's attribute -- year
$year = new DOMAttr('year', '1920');
$name->appendChild($year);
$book->appendChild($name);
//story node
$story = $xmlObject->createElement('story');
$title = $xmlObject->createElement('title', 'Redrevolution');
$quote = $xmlObject->createElement('quote', 'LeaveoffHunan');
$story->appendChild($title);
$story->appendChild($quote);
$book->appendChild($story);
$books->appendChild($book);
if ($xmlObject->save('xml/books.xml') != false){
echo 'success';
}else{
echo 'error';
}
The content of books.xml is only one line:
<?xml version="1.0" encoding="utf-8"?>
the other node is non-existent. Are there any errors in my code?
I forget append the books node to $xmlObject.
add:
$xmlObject->appendChild($books);

Categories