Getting SimpleXMLElement to include the encoding in output - php

This:
$XML = new SimpleXMLElement("<foo />");
echo($XML->asXML());
...outputs this:
<?xml version="1.0"?>
<foo/>
But I want it to output the encoding, too:
<?xml version="1.0" encoding="UTF-8"?>
<foo/>
Is there some way to tell SimpleXMLElement to include the encoding attribute of the <?xml?> tag? Aside from doing this:
$XML = new SimpleXMLElement("<?xml version='1.0' encoding='utf-8'?><foo />");
echo($XML->asXML());
Which works, but it's annoying to have to manually specify the version and encoding.
Assume for the purposes of this question that I cannot use DOMDocument instead.

You can try this, but you must use simplexml_load_string for $xml
$xml // Your main SimpleXMLElement
$xml->addAttribute('encoding', 'UTF-8');
Or you can still use other means to add the encoding to your output.
Simple Replacement
$outputXML=str_replace('<?xml version="1.0"?>', '<?xml version="1.0" encoding="UTF-8"?>', $outputXML);
Regular Expressions
$outputXML=preg_replace('/<\?\s*xml([^\s]*)\?>/' '<?xml $1 encoding="UTF-8"?>', $outputXML);
DOMDocument - I know you said you don't want to use DOMDocument, but here is an example
$xml = dom_import_simplexml($simpleXML);
$xml->xmlEncoding = 'UTF-8';
$outputXML = $xml->saveXML();
You can wrap this code into a function that receives a parameter $encoding and adds it to the

Simple and clear only do this
$XMLRoot = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><element></element>');
OutPut
<?xml version="1.0" encoding="UTF-8"?>
<element></element>
to add attributes in element only use
$XMLRoot->addAttribute('name','juan');
to add child use
$childElement = $XMLRoot->addChild('elementChild');
$childElement->addAttribute('attribName','somthing');

The DOMDoc proposal of Cristian Toma seems a good approach if the document isn't too heavy. You could wrap it up in something like this:
private function changeEncoding(string $xml, string $encoding) {
$dom = new \DOMDocument();
$dom->loadXML($xml);
$dom->encoding = $encoding;
return $dom->saveXML();
}
Comes in useful when you don't have access to the serializer producing the xml.

I would say you will need to do this on creation of each XML object. Even if SimpleXMLElement had a way of setting it you would still need to set it as I guess it would be possible for the object to pick a valid default.
Maybe create a constant and Create objects like this
$XML = new SimpleXMLElement($XMLNamespace . "<foo />");
echo($XML->asXML());

If you don't specify an encoding, SimpleXML cannot (sanely) guess which one you intended.

Related

Convert array to XML with both tags on empty value [duplicate]

I want to generate xml by using php simplexml.
$xml = new SimpleXMLElement('<xml/>');
$output = $xml->addChild('child1');
$output->addChild('child2', "value");
$output->addChild('noValue', '');
Header('Content-type: text/xml');
print($xml->asXML());
The output is
<xml>
<child1>
<child2>value</child2>
<noValue/>
</child1>
</xml>
What I want is if the tag has no value it should display like this
<noValue></noValue>
I've tried using LIBXML_NOEMPTYTAG from Turn OFF self-closing tags in SimpleXML for PHP?
I've tried $xml = new SimpleXMLElement('<xml/>', LIBXML_NOEMPTYTAG); and it doesn't work. So I don't know where to put the LIBXML_NOEMPTYTAG
LIBXML_NOEMPTYTAG does not work with simplexml, per the spec:
This option is currently just available in the DOMDocument::save and DOMDocument::saveXML functions.
To achieve what you're after, you need to convert the simplexml object to a DOMDocument object:
$xml = new SimpleXMLElement('<xml/>');
$child1 = $xml->addChild('child1');
$child1->addChild('child2', "value");
$child1->addChild('noValue', '');
$dom_sxe = dom_import_simplexml($xml); // Returns a DomElement object
$dom_output = new DOMDocument('1.0');
$dom_output->formatOutput = true;
$dom_sxe = $dom_output->importNode($dom_sxe, true);
$dom_sxe = $dom_output->appendChild($dom_sxe);
echo $dom_output->saveXML($dom_output, LIBXML_NOEMPTYTAG);
which returns:
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<child1>
<child2>value</child2>
<noValue></noValue>
</child1>
</xml>
Something worth pointing out... the likely reason that the NOEMPTYTAG option is available for DOMDocument and not simplexml is that empty elements are not considered valid XML, while the DOM specification allows for them. You are banging your head against the wall to get invalid XML, which may suggest that the valid self-closing empty element would work just as well.
Despite the quite lengthy answers already given - which are not particularly wrong and do shed some light into some libxml library internals and it's PHP binding - you're most likely looking for:
$output->noValue = '';
To add an open tag, empty node-value and end tag (beautified, demo is here: http://3v4l.org/S2PKc):
<?xml version="1.0"?>
<xml>
<child1>
<child2>value</child2>
<noValue></noValue>
</child1>
</xml>
Just noting as it seems it has been overlooked with the existing answers.
Since Simple XML is proving troublesome, perhaps XMLWriter could do what you want.
Here's a fiddle
<?php
$oXMLWriter = new XMLWriter;
$oXMLWriter->openMemory();
$oXMLWriter->startDocument('1.0', 'UTF-8');
$oXMLWriter->startElement('xml');
$oXMLWriter->writeElement('child1', 'Hello world!!');
$oXMLWriter->writeElement('noValue', '');
$oXMLWriter->endElement();
$oXMLWriter->endDocument();
echo htmlentities($oXMLWriter->outputMemory(TRUE));
?>
Output:
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<child1>Hello world!!</child1>
<noValue></noValue>
</xml>
Extending from my comments (some got deleted):
The behavior depends on your environment. This same code:
$xml = new SimpleXMLElement('<xml/>', LIBXML_NOEMPTYTAG);
$output = $xml->addChild('child1');
$output->addChild('child2', "value");
$output->addChild('noValue', '');
echo $xml->asXML();
In 3v4l.org and Ideone.com, it produces self-closing tag;
In eval.in, codepad.org and on my localhost (PHP 5.3/5.4, libXML 2.7, Windows), it produces empty tag.
Since according to PHP document, LIBXML_NOEMPTYTAG only (guarenteed to) work in DOM, you may want to try DOM for ensurance:
$dom=new DOMDocument("1.0","UTF-8");
$dom->formatOutput=true;
$root=$dom->createElement("xml");
$dom->appendChild($root);
$child1=$dom->createElement("child1");
$root->appendChild($child1);
$node=$dom->createElement("child2");
$node->appendChild($dom->createTextNode("value"));
$child1->appendChild($node);
$node=$dom->createElement("noValue");
$child1->appendChild($node);
echo $dom->saveXML($dom,LIBXML_NOEMPTYTAG);
3v4l.org demo.
Edit:
All the above online demo site uses Content-Type: text/plain by default. If you want to directly output XML to browser as a standalone resource, you can specify the header before output:
header("Content-Type: text/xml");
echo $dom->saveXML($dom,LIBXML_NOEMPTYTAG);
I had to get the child node and asign to the nodeValue property an empty string, and the xml close tag appears.
$output->childNodes[1]->nodeValue = '';
Greetings.

php export xml CDATA escaped

I am trying to export xml with CDATA tags. I use the following code:
$xml_product = $xml_products->addChild('product');
$xml_product->addChild('mychild', htmlentities("<![CDATA[" . $mytext . "]]>"));
The problem is that I get CDATA tags < and > escaped with < and > like following:
<mychild><![CDATA[My some long long long text]]></mychild>
but I need:
<mychild><![CDATA[My some long long long text]]></mychild>
If I use htmlentities() I get lots of errors like tag raquo is not defined etc... though there are no any such tags in my text. Probably htmlentities() tries to parse my text inside CDATA and convert it, but I dont want it either.
Any ideas how to fix that? Thank you.
UPD_1 My function which saves xml to file:
public static function saveFormattedXmlFile($simpleXMLElement, $output_file) {
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML(urldecode($simpleXMLElement->asXML()));
$dom->save($output_file);
}
A short example of how to add a CData section, note the way it skips into using DOMDocument to add the CData section in. The code builds up a <product> element, $xml_product has a new element <mychild> created in it. This newNode is then imported into a DOMElement using dom_import_simplexml. It then uses the DOMDocument createCDATASection method to properly create the appropriate bit and adds it back into the node.
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><Products />');
$xml_product = $xml->addChild('product');
$newNode = $xml_product->addChild('mychild');
$mytext = "<html></html>";
$node = dom_import_simplexml($newNode);
$cdata = $node->ownerDocument->createCDATASection($mytext);
$node->appendChild($cdata);
echo $xml->asXML();
This example outputs...
<?xml version="1.0" encoding="UTF-8"?>
<Products><product><mychild><![CDATA[<html></html>]]></mychild></product></Products>

append XML literal to DOMDocument in php without escaping

I have a string that represents nodes I'd like to append to a DOMDocument in PHP, but when I add it as a value to an element, it gets escaped. Is there a way to append a chunk of XML to a DOMDocument without it getting escaped - and with the one string addition, several nodes getting added?
Here's an example of what I'm trying to do:
$string = <<<XML
<myNode>
<OtherNode>value</OtherNode>
</myNode>
XML;
$domDoc = new DOMDocument();
$xml_id = $domDoc->createElement('mydata');
$value = $domDoc->createTextNode($string);
$xml_id->appendChild($value);
$subNode = $domDoc->appendChild($xml_id);
echo $domDoc->saveXML();
Currently, however the output looks like this:
<?xml version="1.0"?>
<mydata> <myNode>
<OtherNode>value</OtherNode>
</myNode></mydata>
Is there a way to make it look like this?
<?xml version="1.0"?>
<mydata>
<myNode>
<OtherNode>value</OtherNode>
</myNode>
</mydata>
if I'm not incorrect, you actually should create a documentFragment and append the XML literal to that. Then you should append the documentFragment to the $xml_id and then you should append $xml_id to the $domDoc
$domDoc = new DOMDocument();
$xml_id = $domDoc->createElement('mydata');
$frag = $domDoc->createDocumentFragment();
$frag->appendXML($string);
$xml_id->appendChild($frag);
$domDoc->appendChild($xml_id);

Adding namespace to XML

I'm creating XML response for the one of our clients with the namespace URLs in that using PHP. I'm expecting the output as follows,
<?xml version="1.0" encoding="UTF-8"?>
<ns3:userResponse xmlns:ns3="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://www.w3.org/2001/XMLSchema">
<Content>
<field1>fieldvalue1</field1>
</Content>
</ns3:userResponse>
But by using the following code,
<?php
// create a new XML document
$doc = new DomDocument('1.0', 'UTF-8');
// create root node
$root = $doc->createElementNS('http://www.w3.org/2001/XMLSchema-instance', 'ns3:userResponse');
$root = $doc->appendChild($root);
$root->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'ns1:schemaLocation','');
$root->setAttributeNS('http://www.w3.org/2001/XMLSchema', 'ns2:schemaLocation','');
// add node for each row
$occ = $doc->createElement('Content');
$occ = $root->appendChild($occ);
$child = $doc->createElement("field1");
$child = $occ->appendChild($child);
$value = $doc->createTextNode('fieldvalue1');
$value = $child->appendChild($value);
// get completed xml document
$xml_string = $doc->saveXML();
echo $xml_string;
DEMO:
The demo is here, http://codepad.org/11W9dLU9
Here the problem is, the third attribute is mandatory attribute for the setAttributeNS PHP function. So, i'm getting the output as,
<?xml version="1.0" encoding="UTF-8"?>
<ns3:userResponse xmlns:ns3="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://www.w3.org/2001/XMLSchema" ns3:schemaLocation="" ns2:schemaLocation="">
<Content>
<field1>fieldvalue1</field1>
</Content>
</ns3:userResponse>
So, is there anyway to remove that ns3:schemaLocation and ns2:schemaLocation which is coming with empty value? I googled a lot but couldn't able to find any useful answers.
Any idea on this would be so great. Please help.
You create this attributes:
$root->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'ns1:schemaLocation','');
$root->setAttributeNS('http://www.w3.org/2001/XMLSchema', 'ns2:schemaLocation','');
remove this lines and they will be removed.
If you want to add some xmlns without using it in code is:
$attr_ns = $doc->createAttributeNS( 'http://www.w3.org/2001/XMLSchema', 'ns2:attr' );
Read this comment: http://php.net/manual/pl/domdocument.createattributens.php#98210

How to prevent self closing tag in php simplexml

I want to generate xml by using php simplexml.
$xml = new SimpleXMLElement('<xml/>');
$output = $xml->addChild('child1');
$output->addChild('child2', "value");
$output->addChild('noValue', '');
Header('Content-type: text/xml');
print($xml->asXML());
The output is
<xml>
<child1>
<child2>value</child2>
<noValue/>
</child1>
</xml>
What I want is if the tag has no value it should display like this
<noValue></noValue>
I've tried using LIBXML_NOEMPTYTAG from Turn OFF self-closing tags in SimpleXML for PHP?
I've tried $xml = new SimpleXMLElement('<xml/>', LIBXML_NOEMPTYTAG); and it doesn't work. So I don't know where to put the LIBXML_NOEMPTYTAG
LIBXML_NOEMPTYTAG does not work with simplexml, per the spec:
This option is currently just available in the DOMDocument::save and DOMDocument::saveXML functions.
To achieve what you're after, you need to convert the simplexml object to a DOMDocument object:
$xml = new SimpleXMLElement('<xml/>');
$child1 = $xml->addChild('child1');
$child1->addChild('child2', "value");
$child1->addChild('noValue', '');
$dom_sxe = dom_import_simplexml($xml); // Returns a DomElement object
$dom_output = new DOMDocument('1.0');
$dom_output->formatOutput = true;
$dom_sxe = $dom_output->importNode($dom_sxe, true);
$dom_sxe = $dom_output->appendChild($dom_sxe);
echo $dom_output->saveXML($dom_output, LIBXML_NOEMPTYTAG);
which returns:
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<child1>
<child2>value</child2>
<noValue></noValue>
</child1>
</xml>
Something worth pointing out... the likely reason that the NOEMPTYTAG option is available for DOMDocument and not simplexml is that empty elements are not considered valid XML, while the DOM specification allows for them. You are banging your head against the wall to get invalid XML, which may suggest that the valid self-closing empty element would work just as well.
Despite the quite lengthy answers already given - which are not particularly wrong and do shed some light into some libxml library internals and it's PHP binding - you're most likely looking for:
$output->noValue = '';
To add an open tag, empty node-value and end tag (beautified, demo is here: http://3v4l.org/S2PKc):
<?xml version="1.0"?>
<xml>
<child1>
<child2>value</child2>
<noValue></noValue>
</child1>
</xml>
Just noting as it seems it has been overlooked with the existing answers.
Since Simple XML is proving troublesome, perhaps XMLWriter could do what you want.
Here's a fiddle
<?php
$oXMLWriter = new XMLWriter;
$oXMLWriter->openMemory();
$oXMLWriter->startDocument('1.0', 'UTF-8');
$oXMLWriter->startElement('xml');
$oXMLWriter->writeElement('child1', 'Hello world!!');
$oXMLWriter->writeElement('noValue', '');
$oXMLWriter->endElement();
$oXMLWriter->endDocument();
echo htmlentities($oXMLWriter->outputMemory(TRUE));
?>
Output:
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<child1>Hello world!!</child1>
<noValue></noValue>
</xml>
Extending from my comments (some got deleted):
The behavior depends on your environment. This same code:
$xml = new SimpleXMLElement('<xml/>', LIBXML_NOEMPTYTAG);
$output = $xml->addChild('child1');
$output->addChild('child2', "value");
$output->addChild('noValue', '');
echo $xml->asXML();
In 3v4l.org and Ideone.com, it produces self-closing tag;
In eval.in, codepad.org and on my localhost (PHP 5.3/5.4, libXML 2.7, Windows), it produces empty tag.
Since according to PHP document, LIBXML_NOEMPTYTAG only (guarenteed to) work in DOM, you may want to try DOM for ensurance:
$dom=new DOMDocument("1.0","UTF-8");
$dom->formatOutput=true;
$root=$dom->createElement("xml");
$dom->appendChild($root);
$child1=$dom->createElement("child1");
$root->appendChild($child1);
$node=$dom->createElement("child2");
$node->appendChild($dom->createTextNode("value"));
$child1->appendChild($node);
$node=$dom->createElement("noValue");
$child1->appendChild($node);
echo $dom->saveXML($dom,LIBXML_NOEMPTYTAG);
3v4l.org demo.
Edit:
All the above online demo site uses Content-Type: text/plain by default. If you want to directly output XML to browser as a standalone resource, you can specify the header before output:
header("Content-Type: text/xml");
echo $dom->saveXML($dom,LIBXML_NOEMPTYTAG);
I had to get the child node and asign to the nodeValue property an empty string, and the xml close tag appears.
$output->childNodes[1]->nodeValue = '';
Greetings.

Categories