CRXML,A Replacement for SimpleXML

Coding Critique is the place to post source code for peer review by other members of DevNetwork. Any kind of code can be posted. Code posted does not have to be limited to PHP. All members are invited to contribute constructive criticism with the goal of improving the code. Posted code should include some background information about it and what areas you specifically would like help with.

Popular code excerpts may be moved to "Code Snippets" by the moderators.

Moderator: General Moderators

CRXML,A Replacement for SimpleXML

Postby max529 » Mon Feb 07, 2011 1:33 pm

Hello Everyone,

Out of the difficulty in using SimpleXML (when it involves namespaces and cdata.) I have created this class using the PHP DOM functions.

This class provides a search function that actually outputs the php statements required to access a certain node....

After loading the XML string, just call the `search` or `dump` function with the name of a node, and the class will print out the nodes and the php statements to be used to access that node, no matter what namespaces they are in.

For example Consider the following (complex) xml fragment

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<GeteBayOfficialTimeResponse xmlns="urn:ebay:apis:eBLBaseComponents">
<Timestamp>2005-10-28T01:01:04.668Z</Timestamp>
<Ack>Success</Ack>
<Version>429</Version>
<Build>e429_intl_Bundled_1949355_R1</Build>
</GeteBayOfficialTimeResponse>
</soapenv:Body>
</soapenv:Envelope>


Syntax: [ Download ] [ Hide ]
print_r($srcXML->search('Timestamp'));


this prints the dump of the array returned by the search function.Please note the 'accessStatement' element . This element shows how the 'Timestamp' node should be accessed.

Array
(
[0] => Array
(
[nodeName] => Timestamp
[namespaceURI] => urn:ebay:apis:eBLBaseComponents
[nodeValue] => 2005-10-28T01:01:04.668Z
[accessStatement] => ...->{'soapenv:Envelope'}->{'soapenv:Body'}->{'urn:ebay:apis:eBLBaseComponents|GeteBayOfficialTimeResponse'}->{'urn:ebay:apis:eBLBaseComponents|Timestamp'}
)

)

Here accessElement contains

Syntax: [ Download ] [ Hide ]
...->{'soapenv:Envelope'}->{'soapenv:Body'}->{'urn:ebay:apis:eBLBaseComponents|GeteBayOfficialTimeResponse'}->{'urn:ebay:apis:eBLBaseComponents|Timestamp'}


so an echo
Syntax: [ Download ] [ Hide ]
echo $srcXML->{'soapenv:Envelope'}->{'soapenv:Body'}->{'urn:ebay:apis:eBLBaseComponents|GeteBayOfficialTimeResponse'}->{'urn:ebay:apis:eBLBaseComponents|Timestamp'}


Will echo '2005-10-28T01:01:04.668Z'

You can search namespaced nodes too using the search function. just use the nodename with prefix as it appears in XML.

for Eg:
Syntax: [ Download ] [ Hide ]
$srcXML->search('soapenv:Body');


Never again you will have to manually find the path to a node in a complex xml string.

Its also super easy to generate XML with this class. Please go through the following examples, or the detailed documentation at

http://crxml.pagodabox.com

or

http://www.phpclasses.org/browse/file/34394.html

You can download the class, documentation and demo script from

http://crxml.pagodabox.com/crxml.tar

To illustrate the XML generation capabilities of this class, I have put an online self guided tutorial at

http://crxml.pagodabox.com/demo.php

The functionality of this class is similar to simpleXML,It implements ALL the functionality of simpleXML and much more.

it differs from simpleXML in the way in which namespaced nodes are addressed. In simpleXML namespaced nodes cannot be addressed directly.
In this class a namespaced node can be addressed directly as

$crxmlObject->{'prefix:nodeName'}


If the node defines a default namespace,ie a namespaceURL with out a prefix, then that node can be addressed as

$crxmlObject->{'http:namespaceURI|nodeName'}


this syntax can be used when generating and also while parsing an XML document.(Please see the example below )

A cdata node can be added using the syntax

$crxmlObject->nodeName = (object) "this is the content of a CDATA node" ;

This makes working with namespaces and CDATA sections a little more convenient, or rather, straightforward ( I hope ).This applies to both generation and xml parsing.It also makes it easy to manipulate existing XML documents. Like copying one node from one XML to another or deleting a node or appending a node to another nodes.

Regarding xml manipulaton, All the xml manipulation can be done using the normal assignment operator and four methods $node->appendTo, $node->appendNode, $node->replaceWith and $node->appendChildren. In the posts below you can see various examples of usage of these functions.

This class supports:-

1. XML Attributes
2. XML Namespaces
3. XML Default Namespaces
3. XML Namespaced attributes
4. CDATA sections

please take a look at this example code which illustrate a simple generation of a namespaced xml string,

Syntax: [ Download ] [ Hide ]
<?php
$xmlOne=new crXml();
$xmlOne->root->{'http://google.com|person|prfx'} = 'sandeep';
echo $xmlOne->xml();
?>

outputs
<?xml version="1.0" encoding="UTF-8"?>
<root>
<prfx:person xmlns:prfx="http://google.com">
Sandeep
</prfx:person>
</root>


Here is the link to the class file

http://crxml.pagodabox.com/crXml.tar

or

http://www.phpclasses.org/browse/download/1/file/34393/name/crXml.php

Here is a detailed documentation about its usage.

http://crxml.pagodabox.com


I am adding a LIVE DEMO so that people can check the class out with out downloading anything. Here is the link

http://crxml.pagodabox.com/demo.php

Please, Please do let me know of your comments.

Regards,
Sandeep/Max.
Last edited by max529 on Tue Feb 21, 2012 12:00 am, edited 16 times in total.
max529
Forum Commoner
 
Posts: 50
Joined: Sat May 19, 2007 4:10 am

Re: CRXML,An XML parser/genertor/editor Class

Postby max529 » Mon Feb 14, 2011 2:38 pm

Hi,

Added a Live demo at http://crxml.pagodabox.com/demo.php in hopes of getting some feedback.

Thank you,
Max/Sandeep
Last edited by max529 on Mon Dec 12, 2011 11:49 am, edited 2 times in total.
max529
Forum Commoner
 
Posts: 50
Joined: Sat May 19, 2007 4:10 am

Re: CRXML,An XML parser/genertor/editor Class

Postby max529 » Fri Feb 18, 2011 7:22 am

hi,

were anyone able to take a look at this class?

moderators, is there some reason this post doesnt recive a single reply even after 100 views.?

I mean, is this normal?

anyway...

Here is a nice little demo by which you can play around with the classes, functionality..

http://crxml.pagodabox.com/demo.php

In the demo, you may want to try examples from the doucmentation at

http://crxml.pagodabox.com

Thanks and regards,
Sandeep
Last edited by max529 on Mon Dec 12, 2011 11:52 am, edited 3 times in total.
max529
Forum Commoner
 
Posts: 50
Joined: Sat May 19, 2007 4:10 am

Re: CRXML,An XML parser/genertor/editor Class

Postby Jonah Bron » Sun Feb 20, 2011 12:54 pm

Haven't looked at the code yet, but that example code you give worries me. Why not use xQuery?

moderators, is there some reason this post doesnt recive a single reply even after 100 views.?

No, no reason.
User avatar
Jonah Bron
DevNet Master
 
Posts: 2765
Joined: Thu Mar 15, 2007 6:28 pm
Location: Redding, California

Re: CRXML,An XML parser/genertor/editor Class

Postby Jonah Bron » Sun Feb 20, 2011 6:38 pm

I looked over the code a bit. It would be nice to see the code broken up into logical blocks. Each function is just a big bunch of code right now. Plus, your indentation is not uniform. More whitespace would be good too. So this:
Syntax: [ Download ] [ Hide ]
function _getNewElement($name,$value=null)
        {
                if(strpos($name,"|")!==false) {
                        list($nameSpaceURI,$localName,$prefix)=explode('|',$name);
                        if(isset($prefix)) {
                                $element=$this->root->_getNode()->createElementNS($nameSpaceURI,"$prefix:$localName",'');
                        } else {
                                $element=$this->root->_getNode()->createElementNS($nameSpaceURI,"$localName",'');
                        }
                        if($value) $element->nodeValue=$value;
                        return $element;
                } else if(strpos($name,":")!==false) {
                        list($prefix,$localName)=explode(':',$name);
                        $nameSpaceURI=$this->root->_getNode()->lookupNamespaceURI($prefix);
                        $element=$this->root->_getNode()->createElementNS($nameSpaceURI,"$prefix:$localName",'');
                        if($value) $element->nodeValue=$value;
                        return $element;
                } else {
                        return new DOMElement($name,$value);
                }
        }

Might become:
Syntax: [ Download ] [ Hide ]
        function _getNewElement($name, $value = null)
        {
                $element = null;
               
                if (strpos($name, "|") !== false) {

                        list($nameSpaceURI, $localName, $prefix) = explode('|', $name);
                        if (isset($prefix)) {
                                $element = $this->root->_getNode()->createElementNS($nameSpaceURI, "$prefix:$localName", '');
                        } else {
                                $element = $this->root->_getNode()->createElementNS($nameSpaceURI, "$localName", '');
                        }
                        if ($value) $element->nodeValue = $value;
                       
                } else if (strpos($name, ":") !== false) {

                        list($prefix, $localName) = explode(':', $name);
                        $nameSpaceURI = $this->root->_getNode()->lookupNamespaceURI($prefix);
                        $element = $this->root->_getNode()->createElementNS($nameSpaceURI, "$prefix:$localName", '');
                        if($value) $element->nodeValue = $value;
                       
                } else {
                        $element = new DOMElement($name, $value);
                }
               
                return $element;

        }

(it's a personal belief of mine that return statements should almost always be at the end :) )

I really recommend you read the Zend Coding Standards. Neat syntax isn't the silver bullet to clean code, but it's a start.

http://framework.zend.com/manual/en/cod ... ndard.html

You should change you class/name to conform to this document for autoloading:

http://groups.google.com/group/php-stan ... osal?pli=1
User avatar
Jonah Bron
DevNet Master
 
Posts: 2765
Joined: Thu Mar 15, 2007 6:28 pm
Location: Redding, California

Re: CRXML,An XML parser/genertor/editor Class

Postby max529 » Mon Feb 21, 2011 12:04 am

Jonah Bron wrote:Haven't looked at the code yet, but that example code you give worries me. Why not use xQuery?.


I have never heard of XQuery, But i was planing to make something like that. Think i wont be doing that.
I googled for XQuery and have gone through its description, But can XQuery generate XML?

I request you to try the demo at [...removed until security holes are fixed...]

And why does that example scares you?

I don't know what happened to my indention, because it shows in my gvim as neatly indented. I think i should use more spaces though. Most of the time I am not sure where to put those, and ends up not using any.

No, no reason


So thats just my luck...


Thanks for the reply,

Sandeep.
max529
Forum Commoner
 
Posts: 50
Joined: Sat May 19, 2007 4:10 am

Re: CRXML,An XML parser/genertor/editor Class

Postby Jonah Bron » Mon Feb 21, 2011 1:26 pm

max529 wrote:But can XQuery generate XML?

Not sure, but I don't think so. But there's no point in creating a new syntax for the same thing. Perhaps you should look it up, and change your code generation syntax to match.

max529 wrote:And why does that example scares you?

My brain says it should look like this:
Syntax: [ Download ] [ Hide ]
<?php
$xmlOne=new crXml();
$xmlOne->root->setTag('xquery', 'sandeep');
echo $xmlOne->xml();
?>

xquery being where the xQuery goes.
User avatar
Jonah Bron
DevNet Master
 
Posts: 2765
Joined: Thu Mar 15, 2007 6:28 pm
Location: Redding, California

Re: CRXML,An XML parser/genertor/editor Class

Postby max529 » Tue Feb 22, 2011 8:12 am

Hi,

All I wanted to make was an interface that all php users will be already familiar with, ie the object and array interface.

If I was to use xpath or xquery in this, there would be no point in making something like this, because such syntax already exists.

There is a simplexml library in php, But for some reason it requires a minimal xml string to start creating XML documents.Also I have found it very hard to use when name spaces are to be used.

As far as i saw, there is no support for xquery in php.

All you want to do with XML, I think you can do easily with this class.

I have added some error reporting to this class also. This means when some thing does not work as intended, the class tries to output a helpful error message..like this

Syntax: [ Download ] [ Hide ]
crXml error:No child 'xsi:featreMember' found for node " HostipLookupResultSet".The avaliable child nodes of node HostipLookupResultSet are
gml:description
gml:name
gml:boundedBy
gml:featureMember


or
Syntax: [ Download ] [ Hide ]
 crXml error:
No child 'xsi:featureMember' with default or specified (xsi) name space found for node HostipLookupResultSet, but found a node, 'featureMember' within namespace 'http://www.opengis.net/gml(prefix:gml)' for same node.Please use format

..->HostipLookupResultSet->{'gml:featureMember'}

to access the above node


do you think this would be helpful?

Sandeep.
max529
Forum Commoner
 
Posts: 50
Joined: Sat May 19, 2007 4:10 am

Re: CRXML,An XML parser/genertor/editor Class

Postby Jonah Bron » Tue Feb 22, 2011 11:46 am

max529 wrote:If I was to use xpath or xquery in this, there would be no point in making something like this, because such syntax already exists.
But why re-invent the wheel? The syntax in your code I'm talking about replacing with xpath is the text in {'...'}.

max529 wrote:As far as i saw, there is no support for xquery in php.
Au contraire, mon frère.

http://php.net/simplexmlelement.xpath
http://php.net/class.domxpath

max529 wrote:I have added some error reporting to this class also. This means when some thing does not work as intended, the class tries to output a helpful error message..like this
Good. I think the best way is to throw exceptions (though some may argue otherwise).

Question: how are attributes defined in your library?
User avatar
Jonah Bron
DevNet Master
 
Posts: 2765
Joined: Thu Mar 15, 2007 6:28 pm
Location: Redding, California

Re: CRXML,An XML parser/genertor/editor Class

Postby max529 » Wed Feb 23, 2011 3:47 am

Hi,

I am not reinventing the wheel,

In the expression

Syntax: [ Download ] [ Hide ]
$xmlOne->root->{'http://google.com|person|prfx'} = 'sandeep';


the part inside the {} ie http://google.com|person|prfx, is 3 segments seprated by '|' charecter.

this is not similar to xpath. xpath uses a syntax that uses '/' to separate parent and child nodes..

but here | is used to separate a nodes namespace from nodename. In the above statement the 3 parts are

the namespaceURI,nodename and the namespace prefix for the same namespace URI.

This syntax is used if the namespace have not been declared using the function `addNameSpace` function.
To illustrate this please consider the XML document

Syntax: [ Download ] [ Hide ]
<?xml version="1.0" encoding="UTF-8"?>
<root>
<person>
<name>
rt
</name>
</person>
</root>
 

This xml is generated in singe line using this class as shown below

Syntax: [ Download ] [ Hide ]
 $crxml->root->person->name = 'rt';
 echo $crxml->xml();


Now if we want to add a namespace to the 'name' node, with a prefix, we can do it in a number of ways.
we can add the namespace defenition to the root node like this

Syntax: [ Download ] [ Hide ]
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:prfx="http://namespaceURI.com">
 <person>
   <prfx:name>
    rt
   </prfx:name>
</person>
</root>


if this is the method you want to use, you have to use the addNameSpace method of the crXml class to add the namespace defenition to the root node as shown below.After this, you can use the prefix to add the namespaced nodes as shown below.

Syntax: [ Download ] [ Hide ]
$root= $crxml->root->addNameSpace(  array  ('prfx'=>'http://namespaceURI.com')    );

$root->person->{'prfx:name'} = 'rt';

 echo $crxml->xml()


We can add the namespace without using a prefix also.as shown below.By using this the namespace becomes the default namespace for all the descendent nodes

Syntax: [ Download ] [ Hide ]
<?xml version="1.0" encoding="UTF-8"?>
<root>
<person>
   <name xmlns="http://namespaceURI.com">
     rt
   </name>
</person>
</root>


If this is the xml you have to generate you have to use the '|' charecter to separrate namespaceURI and the nodename.There is no need to define the URI prior to using the uri in document as shown below.

Syntax: [ Download ] [ Hide ]
$crxml->root->person->{'http://namespaceURI.com|name'} = 'rt';
 echo $crxml->xml();
 


There is also another method by which the namespace declaration appears in the same node for which the namesapce is applied. pls check this xml

Syntax: [ Download ] [ Hide ]
<?xml version="1.0" encoding="UTF-8"?>
<root>
<prfx:person xmlns:prfx="http://google.com">
Sandeep
</prfx:person>
</root>
 

It is for generating this kind of nodes the {'http://google.com|person|prfx'} synatax is used. To generate the above xml you still
only have to use the single line

Syntax: [ Download ] [ Hide ]
$xmlOne->root->{'http://google.com|person|prfx'} = 'sandeep';
echo $xmlOne->xml();


And regarding your questing about attributes, attributes maps to array keys. please check the example xml below.

Syntax: [ Download ] [ Hide ]
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <person sex="male">
       <name>
           sandeep
       </name>
   </person>
</root>


To genareate this you can use the following code

Syntax: [ Download ] [ Hide ]

$person= $crxml->root->person;

$person->name = 'sandeep';
$person['sex'] = 'male';
echo $crxml->xml();

 


The attributes can be accessed using the same syntax also for eg
echo $crxml->root->person['sex'] will output 'male' . Attributes can use namespaces also using the syntax person['prfx:name']

Thanks for reading,
Sandeep.
max529
Forum Commoner
 
Posts: 50
Joined: Sat May 19, 2007 4:10 am

Re: CRXML,An XML parser/genertor/editor Class

Postby Jonah Bron » Wed Feb 23, 2011 11:08 am

Ahhhh. Now that I understand it more, it's actually pretty cool. I want to look a bit more at the source code.
User avatar
Jonah Bron
DevNet Master
 
Posts: 2765
Joined: Thu Mar 15, 2007 6:28 pm
Location: Redding, California

Re: CRXML,An XML parser/genertor/editor Class

Postby max529 » Wed Feb 23, 2011 1:29 pm

Thanks Jonah...
max529
Forum Commoner
 
Posts: 50
Joined: Sat May 19, 2007 4:10 am

Re: CRXML,An XML parser/genertor/editor Class

Postby max529 » Thu Feb 24, 2011 4:25 am

Hi,

I am adding another example in which one node from one xml doc is copied to another xml doc using this class.

Source XML

Syntax: [ Download ] [ Hide ]
<?xml version="1.0" encoding="utf-8"?>
<records>
<person age='25' sex='male'>
        <name>
                John
        </name>
</person>
<person age='35' sex='female'>
        <name>
                Ann
        </name>
</person>
</records>


Destination XML

Syntax: [ Download ] [ Hide ]
<?xml version="1.0" encoding="utf-8"?>
<records>
<person age='15' sex="male">
        <name>
                Max
        </name>
</person>
<person age='32' sex='female'>
        <name>
                Liz
        </name>
</person>
</records>


The below code copies the 2nd person node from ie. the 'Ann' node from first xml to a new node in the second XML.
$d and $s are destination and source crxml objects.
Syntax: [ Download ] [ Hide ]
$d->records->person[2] = $s->records->person[1];


Thre resulting XML is

Syntax: [ Download ] [ Hide ]
<?xml version="1.0" encoding="UTF-8"?>
<records>
<person age="15" sex="male">
        <name>
                Max
        </name>
</person>
<person age="32" sex="female">
        <name>
                Liz
        </name>
</person>
<person age="35" sex="female">

        <name>
                Ann
        </name>
</person></records>
 


The full code is given below.


Syntax: [ Download ] [ Hide ]
<?php
include '../crXml.php';

$s = new crXml('1.0','UTF-8');
$d = new crXml('1.0','UTF-8');

$srcXML = <<<EOB
<?xml version="1.0" encoding="utf-8"?>
<records>
<person age='25' sex='male'>
        <name>
                John
        </name>
</person>
<person age='35' sex='female'>
        <name>
                Ann
        </name>
</person>
</records>
EOB
;

$dstXML = <<<EOB
<?xml version="1.0" encoding="utf-8"?>
<records>
<person age='15' sex="male">
        <name>
                Max
        </name>
</person>
<person age='32' sex='female'>
        <name>
                Liz
        </name>
</person>
</records>
EOB
;

$s->loadXML($srcXML);
$d->loadXML($dstXML);

$d->records->person[2] = $s->records->person[1];

echo $d->xml();


during an assignment the following steps are carried out

1.the destination node is emptied and all the attribtues removed
2.all the inner nodes and attributes are copied from source node into the destination node
3.No modification is made to the destination node name.

if the nodename also should be copied, then you are replacing the destination node with the source node.
For this you have to use the function $node->replaceWith($sourceNode) function.

If you want a node to be appended to another nodes children, you can use the appendTo function.

Syntax: [ Download ] [ Hide ]
 $s->records->person[1]->appendTo( $d->records );
 


Here the $s->records->person[1] node is appended to the `$d->records` nodes children. This can be useful if you dont know howmany child nodes the `records` node have

if you have to replace the second node, you have to call the replaceWith function as shown below.



Syntax: [ Download ] [ Hide ]

$d->records->person[1]->replaceWith( $s->records->person[1]);


The resulting XML in $d would be
Syntax: [ Download ] [ Hide ]
<?xml version="1.0" encoding="UTF-8"?>
<records>
<person age="15" sex="male">
        <name>
                Max
        </name>
</person>
<person age="32" sex="female">
        <name>
                Ann
        </name>
</person>
</records>


As the above mentioned behavior has been added recently, Please download the latest version of the class from .

http://www.phpclasses.org/browse/downlo ... /crXml.php

thankyou for reading,

Sandeep.
max529
Forum Commoner
 
Posts: 50
Joined: Sat May 19, 2007 4:10 am

Re: CRXML,An XML parser/genertor/editor Class

Postby max529 » Fri Mar 04, 2011 11:10 pm

hellooooo.....please, I need some feedback on this class......
max529
Forum Commoner
 
Posts: 50
Joined: Sat May 19, 2007 4:10 am

Re: CRXML,A Replacement for SimpleXML

Postby max529 » Fri Apr 01, 2011 11:30 pm

hi guys,

This class won the PHP Programming Innovation Award for february 2011 at phpclasses.org. Leting you all know Just in case it makes any difference, so that some one in here will take a look.....

Thanks
Sandeep
max529
Forum Commoner
 
Posts: 50
Joined: Sat May 19, 2007 4:10 am

Next

Return to Coding Critique

Who is online

Users browsing this forum: No registered users and 2 guests