retrieve html and XML from a string with php - php

My project is to use CKEditor and create a plugin to create chart inside the page which will display the result
(in CKEditor just an img will appear when you use the plugin).
The plugin is already created,
when you use it, XML with the value and attribute needed is created inside CKEditor.
So the XML for the chart exist with writing text (format as <p> by CKEditor).
When you save inside the CKEditor, the XML and the text as HTML are sent to the database inside a string
(when I retrieve data from CKEditor it send a string).
Inside the database it is stored like this:
<?xml version="1.0"?>
<configuration>
<onglet pos="1" name="test">
<wysiwyg>
<code>
<p>test</p>
<p><graphique drawer="Line" interval="2" periode="semaine" titre="test" type="Relative">
<serie marqueur="Normal">
<index serial="---" type="di">3</index>
<typegroupe></typegroupe>
<intervalgroup></intervalgroup>
<periodgroup></periodgroup>
<groupverif>non</groupverif>
<unite>Kwh</unite>
<legend>test2</legend>
<color>#000000</color>
</serie>
</graphique></p>
</code>
</wysiwyg>
</onglet>
</configuration>
I get it inside a php page to displays my text and chart from CKEditor
Like this:
$test=200; //ID
$testxml=loadxml($test);
$testonglet=$testxml->onglet;
$testwysiwyg=$testonglet->wysiwyg;
$testcode=$testwysiwyg->code;
loadxml is a php function in another file:
$loadXml = THE QUERY TO RETRIEVE THE XML FROM THE DB
$reqload = mysql_fetch_array(mysql_query($loadXml));
$decode = html_entity_decode($reqload[0]);
$xml = simplexml_load_string($decode);
return $xml;
Now if I do var_dump($testcode);
I got:
object(SimpleXMLElement)#6 (1) { [0]=> string(403) "
test
4nonKwhtest2#000000
test après graph
" }
test and test après graph are just text but the 4nonKwhtest2#000000 are the XML value from the plugin chart.
I would like to parse the string to retrive the text and the XML (with his structure since I need it to create the chart with php).
I have already tested:
$testXML = Simplexml_load_string($testcode);
var_dump($testXML);
It gave me:
bool(false)
I have the same from XMLReader.
I also tested:
$dom = new DOMDocument();
$dom->loadHTML($testcode);
It gave something with the text but I couldn't retrieve my XML from it.
I don't know how to handle this anymore, it's the first time I use PHP
I hope it's more clear like this (sorry for my english).

Basically you have an XML document that contains another XML fragment as a text node.
That means you need to load the outer XML document first, read the text node and append the XML fragment to a new XML document.
Load The Outer XML / Read The Fragment:
DOMXpath::evaluate() allows to fetch nodes and values from a XML DOM using XPath expression.
$outer = new DOMDocument();
$outer->loadXml($xml);
$xpath = new DOMXPath($outer);
$innerXml = $xpath->evaluate('string(/configuration/onglet/wysiwyg/code)');
echo $innerXml;
Output:
<p>test</p>
<p><graphique drawer="Line" interval="2" periode="semaine" titre="test" type="Relative">
<serie marqueur="Normal">
<index serial="---" type="di">3</index>
<typegroupe></typegroupe>
<intervalgroup></intervalgroup>
<periodgroup></periodgroup>
<groupverif>non</groupverif>
<unite>Kwh</unite>
<legend>test2</legend>
<color>#000000</color>
</serie>
</graphique></p>
Load The XML Fragment
XML documents have a single root/document element node, so the XML in the case is a fragment. For easy reading it needs the single root node. So lets create a document with a body node and append the fragment to it:
$inner = new DOMDocument();
$inner->appendChild($inner->createElement('body'));
$fragment = $inner->createDocumentFragment();
$fragment->appendXml($innerXml);
$inner->documentElement->appendChild($fragment);
echo $inner->saveXml();
Output:
<?xml version="1.0"?>
<body>
<p>test</p>
<p><graphique drawer="Line" interval="2" periode="semaine" titre="test" type="Relative">
<serie marqueur="Normal">
<index serial="---" type="di">3</index>
<typegroupe></typegroupe>
<intervalgroup></intervalgroup>
<periodgroup></periodgroup>
<groupverif>non</groupverif>
<unite>Kwh</unite>
<legend>test2</legend>
<color>#000000</color>
</serie>
</graphique></p>
</body>
The element name doesn't matter, but body fits the p elements.
Read Data From The New Document
Now it is possible to create an DOMXPath instance for the document and fetch data from it.
$xpath = new DOMXPath($inner);
foreach ($xpath->evaluate('//graphique') as $graphique) {
var_dump(
[
'drawer' => $graphique->getAttribute('drawer'),
'serie-color' => $xpath->evaluate('string(serie/color)', $graphique)
]
);
}
Output:
array(2) {
["drawer"]=>
string(4) "Line"
["serie-color"]=>
string(7) "#000000"
}

Related

Adding or Updating XML Node PHP? [duplicate]

I just wanted to ask how I can insert a new node in an XML using PHP. my XML file (questions.xml) is given below
<?xml version="1.0" encoding="UTF-8"?>
<Quiz>
<topic text="Preparation for Exam">
<subtopic text="Science" />
<subtopic text="Maths" />
<subtopic text="english" />
</topic>
</Quiz>
I want to add a new "subtopic" with the "text" attribute, that is "geography". How can I do this using PHP? Thanks in advance though.
well my code is
<?php
$xmldoc = new DOMDocument();
$xmldoc->load('questions.xml');
$root = $xmldoc->firstChild;
$newElement = $xmldoc->createElement('subtopic');
$root->appendChild($newElement);
// $newText = $xmldoc->createTextNode('geology');
// $newElement->appendChild($newText);
$xmldoc->save('questions.xml');
?>
I'd use SimpleXML for this. It would look somehow like this:
// Open and parse the XML file
$xml = simplexml_load_file("questions.xml");
// Create a child in the first topic node
$child = $xml->topic[0]->addChild("subtopic");
// Add the text attribute
$child->addAttribute("text", "geography");
You can either display the new XML code with echo or store it in a file.
// Display the new XML code
echo $xml->asXML();
// Store new XML code in questions.xml
$xml->asXML("questions.xml");
The best and safe way is to load your XML document into a PHP DOMDocument object, and then go to your desired node, add a child, and finally save the new version of the XML into a file.
Take a look at the documentation : DOMDocument
Example of code:
// open and load a XML file
$dom = new DomDocument();
$dom->load('your_file.xml');
// Apply some modification
$specificNode = $dom->getElementsByTagName('node_to_catch');
$newSubTopic = $xmldoc->createElement('subtopic');
$newSubTopicText = $xmldoc->createTextNode('geography');
$newSubTopic->appendChild($newSubTopicText);
$specificNode->appendChild($newSubTopic);
// Save the new version of the file
$dom->save('your_file_v2.xml');
You can use PHP's Simple XML. You have to read the file content, add the node with Simple XML and write the content back.

how to insert data inside tag XML

I want to create dynamic tags in XML using PHP
like this : <wsse:Username>fqsuser01</wsse:Username>
the main thing is that I want the tags will change the value inside ---> "wsse"
(like this value)
what I need to do? to create this XML file wite PHP?
Thanks,
For this purpose you can use XMLWriter for example (another option is SimpleXML). Both option are in PHP core so any third party libraries aren't needed. wsse is a namespace - more about them you can read here
I also share with you some example code:
<?php
//create a new xmlwriter object
$xml = new XMLWriter();
//using memory for string output
$xml->openMemory();
//set the indentation to true (if false all the xml will be written on one line)
$xml->setIndent(true);
//create the document tag, you can specify the version and encoding here
$xml->startDocument();
//Create an element
$xml->startElement("root");
//Write to the element
$xml->writeElement("r1:id", "1");
$xml->writeElement("r2:id", "2");
$xml->writeElement("r3:id", "3");
$xml->endElement(); //End the element
//output the xml
echo $xml->outputMemory();
?>
Result:
<?xml version="1.0"?>
<root>
<r1:id>1</r1:id>
<r2:id>2</r2:id>
<r3:id>3</r3:id>
</root>
You could use a string and convert it to XML using simplexml_load_string(). The string must be well formed.
<?php
$usernames= array(
'username01',
'username02',
'username03'
);
$xml_string = '<wsse:Usernames>';
foreach($usernames as $username ){
$xml_string .= "<wsse:Username>$username</wsse:Username>";
}
$xml_string .= '</wsse:Usernames>';
$note=
<<<XML
$xml_string
XML; //backspace this line all the way to the left
$xml=simplexml_load_string($note);
?>
If you wanted to be able to change the namespaces on each XML element you would do something very similar to what is shown above. (Form a string with dynamic namespaces)
The XML portion that I instructed you to backspace all of the way has weird behavior. See https://www.w3schools.com/php/func_simplexml_load_string.asp for an example that you can copy & paste.

PHP: Keeping HTML inside XML node without CDATA

I've got an xml like this:
<father>
<son>Text with <b>HTML</b>.</son>
</father>
I'm using simplexml_load_string to parse it into SimpleXmlElement. Then I get my node like this
$xml->father->son->__toString(); //output: "Text with .", but expected "Text with <b>HTML</b>."
I need to handle simple HTML such as:
<b>text</b> or <br/> inside the xml which is sent by many users.
Me problem is that I can't just ask them to use CDATA because they won't be able to handle it properly, and they are already use to do without.
Also, if it's possible I don't want the file to be edited because the information need to be the one sent by the user.
The function simplexml_load_string simply erase anything inside HTML node and the HTML node itself.
How can I keep the information ?
SOLUTION
To handle the problem I used the asXml as explained by #ThW:
$tmp = $xml->father->son->asXml(); //<son>Text with <b>HTML</b>.</son>
I just added a preg_match to erase the node.
A CDATA section is a character node, just like a text node. But it does less encoding/decoding. This is mostly a downside, actually. On the upside something in a CDATA section might be more readable for a human and it allows for some BC in special cases. (Think HTML script tags.)
For an XML API they are nearly the same. Here is a small DOM example (SimpleXML abstracts to much).
$document = new DOMDocument();
$father = $document->appendChild(
$document->createElement('father')
);
$son = $father->appendChild(
$document->createElement('son')
);
$son->appendChild(
$document->createTextNode('With <b>HTML</b><br>It\'s so nice.')
);
$son = $father->appendChild(
$document->createElement('son')
);
$son->appendChild(
$document->createCDataSection('With <b>HTML</b><br>It\'s so nice.')
);
$document->formatOutput = TRUE;
echo $document->saveXml();
Output:
<?xml version="1.0"?>
<father>
<son>With <b>HTML</b><br>It's so nice.</son>
<son><![CDATA[With <b>HTML</b><br>It's so nice.]]></son>
</father>
As you can see they are serialized very differently - but from the API view they are basically exchangeable. If you're using an XML parser the value you get back should be the same in both cases.
So the first possibility is just letting the HTML fragment be stored in a character node. It is just a string value for the outer XML document itself.
The other way would be using XHTML. XHTML is XML compatible HTML. You can mix an match different XML formats, so you could add the XHTML fragment as part of the outer XML.
That seems to be what you're receiving. But SimpleXML has some problems with mixed nodes. So here is an example how you can read it in DOM.
$xml = <<<'XML'
<father>
<son>With <b>HTML</b><br/>It's so nice.</son>
</father>
XML;
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$result = '';
foreach ($xpath->evaluate('/father/son[1]/node()') as $child) {
$result .= $document->saveXml($child);
}
echo $result;
Output:
With <b>HTML</b><br/>It's so nice.
Basically you need to save each child of the son element as XML.
SimpleXML is based on the same DOM library internally. That allows you to convert a SimpleXMLElement into a DOM node. From there you can again save each child as XML.
$father = new SimpleXMLElement($xml);
$sonNode = dom_import_simplexml($father->son);
$document = $sonNode->ownerDocument;
$result = '';
foreach ($sonNode->childNodes as $child) {
$result .= $document->saveXml($child);
}
echo $result;

Modify existing XML file with DomDocument PHP

I have an existing xml file of the following format:
<root>
<word>
<label></label>
<definition></definition>
</word>
...
</root>
I'm taking in text through input boxes for the word and definition on the page and passing it to the php script via GET. The goal for the php script is to take the user input and add an additional word element containing the nested elements label (contains actual word) and definition (contains word definition) to the XML document vocab.xml.
Here is the script:
<?php
$word = $_GET['word'];
$definition = $_GET['definition'];
$dom = new DomDocument();
$dom->load("vocab.xml");
$root = $dom->documentElement;
$node = $dom->createElement("word");
$node2 = $dom->createElement("label", $word);
$node3 = $dom->createElement("definition", $definition);
$node->appendChild($node2);
$node->appendChild($node3);
$root->appendChild($node);
$dom->asXML("vocab.xml");
?>
As it stands now the script appears to execute correctly but checking the XML file reveals that no changes were made.
DOMDocument has no method asXML(). You need to use save():
$dom->save("vocab.xml");

How store xml file special characters values in its as it is?

I am using my xml file to store special chars.
This is my original file
<root>
<popups>
<popup id="1">
<text1>
<![CDATA[dynamic text popup 2a]]>
</text1>
<text2>
<![CDATA[dynamic text popup 2b]]>
</text2>
</popup>
</popups>
</root>
Now when I use php to save special chars eg , it becomes like that
<root>
<popups>
<popup id="1">
<text1><![CDATA[Hello world]]></text1>
<text2><![CDATA[asassa]]></text2>
</popup>
</popups>
</root>
I have used the following code :
$this->xmlDocument = simplexml_load_file("xml/conf.xml");
$pages_node = $this->xmlDocument->xpath("/root/popups/popup[#id=1]");
$name = $_POST['popup-name'];
$editor1 = trim(strip_tags($_POST['editor1']));
$editor2 = trim(strip_tags($_POST['editor2']));
if (!empty($name)){
if (!empty($editor1)){
$pages_node[0]->text1 = "<![CDATA[".$editor1."]]>";
}
if (!empty($editor2)){
$pages_node[0]->text2 = "<![CDATA[".$editor2."]]>" ;
}
$this->xmlDocument->asXml($this->basePath() . "conf/conf.xml");
}
How can I save the special chars as they are without needing to encode them?
Simplexml is meant to be simple, so there is no such option. dom_import_simplexml can help you create domdocument from simplexml object.
You have to create new instance of DOMDocument, then create CDATA section and put it into imported DOMElement node.
If you are using php DomDocument, you have to create DOMCDATASection and append it to text1/text2 nodes.
If you don't have text1 and text2 nodes, you have to create them first, then appencd cdata node to them and finally append them to popup:
$cdata = $dom->createCDATASection("test");
$text1 = $dom->createElement('text1');
$text1->appendChild($cdata);
$text1 = $dom->createElement('text2');
$text2->appendChild($cdata);
$popupNode->appendChild($text1);
$popupNode->appendChild($text2);

Categories