2011年10月28日 星期五

PHP : XML Create-Add-Edit-Modify using DOM , SimpleXML , XPath

Over the last few working days, I spent a quite a bit of time playing around with XML. While searching through the net, I found few comprehensive PHP XML guides. There never was a ’1 stop all operations’ guide for learning XML.
As such I decided to club together examples of all kinds of operations I ever did on XML in a single post. I hope it benefits others out there who wish to learn more about XML manipulation.
Note : Since the post got quite large, I decided to only use the Tree Map style parsers – DOM & Simple XML.




Operations Performed:
(1) Create XML OR Array to XML Conversion OR CDATA Element Eg
(2) Edit XML – Edit/Modify Element Data (accessed serially)
(3) Edit XML – Edit specific Elements (accessed conditionally)
(4) Edit XML – Element Addition (to queue end)
(5) Edit XML – Element Addition (to queue start)
(6) Edit XML – Element Addition (before a specific node)
(7) Delete Elements (accessed serially)
(8) Delete Elements (accessed conditionally)
(9) Rearrange / Reorder Elements
(10) Display Required data in XML Form itself OR Remove all children nodes save one OR Copy/Clone Node Eg OR Compare/Search non numeric data (like date or time) to get result.

library.xml will be used in all operations.
ps : I have added the indention & spaces outside the tags in the below xml for a presentable xml form.
Remove them before saving your xml file else most of the usual XML functions wont work in the desired manner.

01

02

03

04
<![CDATA[The Fountainhead]]>
05
Ayn Rand
06
300
07

08

09
<![CDATA[The Lord of the Rings]]>
10
J.R.R.Tolkein
11
500
12

13

14
<![CDATA[The Dark Tower]]>
15
Stephen King
16
200
17

18


#######################################
// (1) Create XML OR
Array to XML Conversion OR
CDATA Element Eg
#######################################

// (i) SimpleXML :

01
// Cant create CDATA element for title in SimpleXML.
02
function fnSimpleXMLCreate()
03
{
04
$arr = array(array('isbn'=>'1001', 'pubdate'=>'1943-01-01', 'title'=>'The Fountainhead',
05
'author'=>'Ayn Rand', 'price'=>'300'),
06
array('isbn'=>'1002', 'pubdate'=>'1954-01-01',
07
'title'=>'The Lord of the Rings', 'author'=>'J.R.R.Tolkein',
08
'price'=>'500'),
09
array('isbn'=>'1003', 'pubdate'=>'1982-01-01', 'title'=>'The Dark Tower',
10
'author'=>'Stephen King', 'price'=>'200'));
11

12
$library = new SimpleXMLElement('');
13

14
for($i=0;$i<3;$i++)
15
{
16
$book = $library->addChild('book');
17
$book->addAttribute('isbn', $arr[$i]['isbn']);
18
$book->addAttribute('pubdate', $arr[$i]['pubdate']);
19
$book->addChild('title', $arr[$i]['title']); //cant create CDATA in SimpleXML.
20
$book->addChild('author', $arr[$i]['author']);
21
$book->addChild('price', $arr[$i]['price']);
22
}
23

24
$library->asXML('library.xml');
25
}

// (ii) DOM :

01
function fnDomCreate()
02
{
03
$arr = array(array('isbn'=>'1001', 'pubdate'=>'1943-01-01', 'title'=>'The Fountainhead',
04
'author'=>'Ayn Rand', 'price'=>'300'),
05
array('isbn'=>'1002', 'pubdate'=>'1954-01-01',
06
'title'=>'The Lord of the Rings', 'author'=>'J.R.R.Tolkein',
07
'price'=>'500'),
08
array('isbn'=>'1003', 'pubdate'=>'1982-01-01', 'title'=>'The Dark Tower',
09
'author'=>'Stephen King', 'price'=>'200'));
10

11
$dom = new DOMDocument();
12
$library = $dom->createElement('library');
13
$dom->appendChild($library);
14

15
for($i=0;$i<3;$i++)
16
{
17
$book = $dom->createElement('book');
18
$book->setAttribute('isbn',$arr[$i]['isbn']);
19
$book->setAttribute('pubdate',$arr[$i]['pubdate']);
20

21
//$prop = $dom->createElement('title', $arr[$i]['title']);
22
$prop = $dom->createElement('title');
23
$text = $dom->createCDATASection($arr[$i]['title']);
24
$prop->appendChild($text);
25
$book->appendChild($prop);
26

27
$prop = $dom->createElement('author', $arr[$i]['author']);
28
$book->appendChild($prop);
29
$prop = $dom->createElement('price', $arr[$i]['price']);
30
$book->appendChild($prop);
31
$library->appendChild($book);
32
}
33
//header("Content-type: text/xml");
34
$dom->save('library.xml');
35
}

#######################################
// (2) Edit XML – Edit/Modify Element Data (accessed serially)
#######################################

// (i) SimpleXML :

1
// Edit Last Book Title
2
function fnSimpleXMLEditElementSeq()
3
{
4
$library = new SimpleXMLElement('library.xml',null,true);
5
$num = count($library);
6
$library->book[$num-1]->title .= ' - The Gunslinger';
7
header("Content-type: text/xml");
8
echo $library->asXML();
9
}

// (ii) DOM :

01
//Edit Last Book Title
02
function fnDOMEditElementSeq()
03
{
04
$dom = new DOMDocument();
05
$dom->load('library.xml');
06
$library = $dom->documentElement;
07
$cnt = $library->childNodes->length;
08

09
$library->childNodes->item($cnt-1)->getElementsByTagName('title')->item(0)->nodeValue .= ' Series';
10
// 2nd way #$library->getElementsByTagName('book')->item($cnt-1)->getElementsByTagName('title')->item(0)->nodeValue .= ' Series';
11

12
//3rd Way
13
//$library->childNodes->item($cnt-1)->childNodes->item(0)->nodeValue .= ' Series';
14
header("Content-type: text/xml");
15
echo $dom->saveXML();
16
}

#######################################
// (3) Edit XML – Edit specific Elements (accessed conditionally)
#######################################

// (i) SimpleXML :

1
//Edit Title of book with author J.R.R.Tolkein
2
function fnSimpleXMLEditElementCond()
3
{
4
$library = new SimpleXMLElement('library.xml',null,true);
5
$book = $library->xpath('/library/book[author="J.R.R.Tolkein"]');
6
$book[0]->title .= ' Series';
7
header("Content-type: text/xml");
8
echo $library->asXML();
9
}

// (ii) DOM (with XPath):

01
//Edit Title of book with author J.R.R.Tolkein
02
function fnDOMEditElementCond()
03
{
04
$dom = new DOMDocument();
05
$dom->load('library.xml');
06
$library = $dom->documentElement;
07
$xpath = new DOMXPath($dom);
08
$result = $xpath->query('/library/book[author="J.R.R.Tolkein"]/title');
09
$result->item(0)->nodeValue .= ' Series';
10
// This will remove the CDATA property of the element.
11
//To retain it, delete this element (see delete eg) & recreate it with CDATA (see create xml eg).
12

13
//2nd Way
14
//$result = $xpath->query('/library/book[author="J.R.R.Tolkein"]');
15
// $result->item(0)->getElementsByTagName('title')->item(0)->nodeValue .= ' Series';
16
header("Content-type: text/xml");
17
echo $dom->saveXML();
18

19
}

#######################################
// (4) Edit XML – Element Addition (to queue end)
#######################################

// (i) SimpleXML :

01
//Add another Book to the end
02
function fnSimpleXMLAddElement2End()
03
{
04
$library = new SimpleXMLElement('library.xml',null,true);
05
$book = $library->addChild('book');
06
$book->addAttribute('isbn', '1004');
07
$book->addAttribute('pubdate', '1960-07-11');
08
$book->addChild('title', "To Kill a Mockingbird");
09
$book->addChild('author', "Harper Lee");
10
$book->addChild('price', "100");
11
header("Content-type: text/xml");
12
echo $library->asXML();
13
}

// (ii) DOM :

01
//Add another Book to the end
02
function fnDOMAddElement2End()
03
{
04
$dom = new DOMDocument();
05
$dom->load('library.xml');
06
$library = $dom->documentElement;
07

08
$book = $dom->createElement('book');
09
$book->setAttribute('isbn','1000');
10
$book->setAttribute('pubdate','1960-07-11');
11

12
$prop = $dom->createElement('title');
13
$text = $dom->createTextNode('To Kill a Mockingbird');
14
$prop->appendChild($text);
15
$book->appendChild($prop);
16

17
$prop = $dom->createElement('author','Harper Lee');
18
$book->appendChild($prop);
19
$prop = $dom->createElement('price','100');
20
$book->appendChild($prop);
21

22
$library->appendChild($book);
23
header("Content-type: text/xml");
24
echo $dom->saveXML();
25
}

#######################################
//(5) Edit XML – Element Addition (to queue start)
#######################################

// (i) SimpleXML :

01
// Add a Book to List Start
02
// Insert Before Functionality not present in SimpleXML
03
// We can integrate DOM with SimpleXML to do it.
04
function fnSimpleXMLAddElement2Start()
05
{
06
$libSimple = new SimpleXMLElement('library.xml',null,true);
07
$libDom = dom_import_simplexml($libSimple);
08

09
$dom = new DOMDocument();
10
//returns a copy of the node to import
11
$libDom = $dom->importNode($libDom, true);
12
//associate it with the current document.
13
$dom->appendChild($libDom);
14

15
fnDOMAddElement2Start($dom); //see below DOM function
16
}

// (ii) DOM :

01
function fnDOMAddElement2Start($dom='')
02
{
03
if(!$dom)
04
{
05
$dom = new DOMDocument();
06
$dom->load('library.xml');
07
}
08
$library = $dom->documentElement;
09
#var_dump($library->childNodes->item(0)->parentNode->nodeName);
10
$book = $dom->createElement('book');
11
$book->setAttribute('isbn','1000');
12
$book->setAttribute('pubdate','1960-07-11');
13

14
$prop = $dom->createElement('title','To Kill a Mockingbird');
15
$book->appendChild($prop);
16
$prop = $dom->createElement('author','Harper Lee');
17
$book->appendChild($prop);
18
$prop = $dom->createElement('price','100');
19
$book->appendChild($prop);
20

21
$library->childNodes->item(0)->parentNode->insertBefore($book,$library->childNodes->item(0));
22
header("Content-type: text/xml");
23
echo $dom->saveXML();
24
}

#######################################
// (6) Edit XML – Element Addition (before a specific node)
#######################################

// (i) SimpleXML :

01
// Add a Book Before attribute isbn 1002
02
// Insert Before Functionality not present in SimpleXML
03
// We can integrate DOM with SimpleXML to do it.
04
function fnSimpleXMLAddElementCond()
05
{
06
$libSimple = new SimpleXMLElement('library.xml',null,true);
07
$libDom = dom_import_simplexml($libSimple);
08

09
$dom = new DOMDocument();
10
//returns a copy of the node to import
11
$libDom = $dom->importNode($libDom, true);
12
//associate it with the current document.
13
$dom->appendChild($libDom);
14

15
fnDOMAddElementCond($dom); //see below DOM eg.
16
}

// (ii) DOM :

01
// Add a Book Before isbn 1002
02
function fnDOMAddElementCond($dom='')
03
{
04
if(!$dom)
05
{
06
$dom = new DOMDocument();
07
$dom->load('library.xml');
08
}
09
$library = $dom->documentElement;
10

11
$book = $dom->createElement('book');
12
$book->setAttribute('isbn','1000');
13
$book->setAttribute('pubdate', '1960-07-11');
14

15
$prop = $dom->createElement('title','To Kill a Mockingbird');
16
$book->appendChild($prop);
17
$prop = $dom->createElement('author','Harper Lee');
18
$book->appendChild($prop);
19
$prop = $dom->createElement('price','100');
20
$book->appendChild($prop);
21

22
$xpath = new DOMXPath($dom);
23
$result = $xpath->query('/library/book[@isbn="1002"]');
24
$library->childNodes->item(0)->parentNode->insertBefore($book,$result->item(0));
25
header("Content-type: text/xml");
26
echo $dom->saveXML();
27
}

#######################################
// (7) Delete Elements (accessed serially)
#######################################

// (i) SimpleXML :

01
// Delete 2nd book
02
function fnSimpleXMLDeleteSeq()
03
{
04
$library = new SimpleXMLElement('library.xml',null,true);
05
//$library->book[1] = null; // this only empties content
06
unset($library->book[1]);
07
header("Content-type: text/xml");
08
echo $library->asXML();
09

10
}

// (ii) DOM :

01
// Delete 2nd Book
02
function fnDOMDeleteSeq()
03
{
04
$dom = new DOMDocument();
05
$dom->load('library.xml');
06
$library = $dom->documentElement;
07

08
$library->childNodes->item(0)->parentNode->removeChild($library->childNodes->item(1));
09

10
header("Content-type: text/xml");
11
echo $dom->saveXML();
12
}

#######################################
// (8) Delete Elements (accessed conditionally)
#######################################

// (i) SimpleXML :

01
// Delete a book with 20002
// Not possible to delete node found via XPath in SimpleXML. See below.
03
function fnSimpleXMLDeleteCond()
04
{
05
$library = new SimpleXMLElement('library.xml',null,true);
06
$book = $library->xpath('/library/book[price>"200" and price<"500"]');
07

08
//Problem here....not able to delete parent node using unset($book[0]);
09
// unset of parent node only works when accessing serially. eg : unset($library->book[0]);
10

11
//header("Content-type: text/xml");
12
//echo $library->asXML();
13

14
}

// (ii) DOM :

01
// Delete the book with 20002
function fnDOMDeleteCond()
03
{
04
$dom = new DOMDocument();
05
$dom->load('library.xml');
06
$library = $dom->documentElement;
07
$xpath = new DOMXPath($dom);
08
$result = $xpath->query('/library/book[price>"200" and price<"500"]');
09
$result->item(0)->parentNode->removeChild($result->item(0));
10
header("Content-type: text/xml");
11
echo $dom->saveXML();
12
}

#######################################
// (9) Rearrange / Reorder Elements
#######################################

// (i) SimpleXML :

01
// Exchange Position of 2nd book with 3rd : fnSimpleXMLRearrange(2,3);
02
// Due to absence of an inbuilt function (DOM has it), we have to make our own function in SimpleXML.
03
//Better to use DOM.
04
function fnSimpleXMLRearrange($num1,$num2)
05
{
06
$libSimple= new SimpleXMLElement('library.xml',null,true);
07
//$library->book[3] = $library->book[0]; // this doesnt work
08

09
$libDom = dom_import_simplexml($libSimple);
10

11
$dom = new DOMDocument();
12
//returns a copy of the node to import
13
$libDom = $dom->importNode($libDom, true);
14
//associate it with the current document.
15
$dom->appendChild($libDom);
16
fnDOMRearrange($num1,$num2,$dom); // see below DOM function
17
}

// (ii) DOM :

01
// Exchange Position of 2nd book with 3rd : fnDOMRearrange(2,3);
02
function fnDOMRearrange($num1,$num2,$dom=0)
03
{
04
if(!$dom)
05
{
06
$dom = new DOMDocument();
07
$dom->load('library.xml');
08
}
09
$dom = new DOMDocument();
10
$dom->load('library.xml');
11
$library = $dom->documentElement;
12

13
$book = $dom->createElement('book');
14
$book->setAttribute('isbn','1000');
15
$book->setAttribute('pubdate','1960-07-11');
16

17
$num1 = fnDOMConvIndex($num1);
18
$num2 = fnDOMConvIndex($num2);
19
$library->childNodes->item(0)->parentNode->insertBefore($library->childNodes->item($num2),$library->childNodes->item($num1));
20
header("Content-type: text/xml");
21
echo $dom->saveXML();
22
}
23
function fnDOMConvIndex($num)
24
{
25
$num = ($num==1)?$num:$num+1;//If its 1 then do nothing.
26
$num = ($num%2)?$num:$num+1; //Always odd index due to nature of DOM Element Index.
27
return $num;
28
}

#######################################
// (10) Display Required data in XML Form itself OR
Remove all children nodes save one OR
Copy/Clone Node Eg OR
Compare/Search non numeric data (like date or time) to get result.
#######################################

// (i) SimpleXML :

1
// Display Books published after 1980 in XML Form itself.
2
// No function to copy node directly in SimpleXML.
3
// Its simpler for this functionality to be implemented in DOM.
4
function fnSimpleXMLDisplayElementCond()
5
{
6
$library = new SimpleXMLElement('library.xml',null,true);
7
$book = $library->xpath('/library/book[translate(@pubdate,"-","")>translate("1980-01-01","-","")]');
8
// Manually create a new structure then add searched data to it (see create xml eg.)
9
}

// (ii) DOM :

01
// Display Books published after 1980 in XML Form itself.
02
function fnDOMDisplayElementCond()
03
{
04
$dom = new DOMDocument();
05
$dom->load('library.xml');
06
$library = $dom->documentElement;
07
$xpath = new DOMXPath($dom);
08

09
// Comparing non numeric standard data
10
$result = $xpath->query('/library/book[translate(@pubdate,"-","")>translate("1980-01-01","-","")]');
11
// For simpler search paramater use this :
12
//$result = $xpath->query('/library/book[author="J.R.R.Tolkein"]');
13

14
// Copy only node & its attributes not its contents.
15
$library = $library->cloneNode(false);
16
// Add the 1 element which is search result.
17
$library->appendChild($result->item(0));
18

19
header("Content-type: text/xml");
20
echo $dom->saveXML($library);
21
}
Lessons Learn’t :
SimpleXML is fantastic for those who will only briefly flirt with XML (or beginners) & perform simple operations on XML.
DOM is an absolute necessity for performing complex operations on XML data. Its learning curve is higher than SimpleXML off course but once you get the hang of it , you will know its very logical.
Use XPath for conditional access to data. For serial access (like last book) XPath is not needed (but u can use it) since I can use normal DOM / SimpleXML node access.

reference : http://quest4knowledge.wordpress.com/2010/09/04/php-xml-create-add-edit-modify-using-dom-simplexml-xpath/

沒有留言:

wibiya widget