SimpleXML query - php

hi my xml has this structure
<articles>
<article>
<title></title>
<text></text>
<notes>
<note>
<code></code>
<text></text>
</note>
<note>
<code></code>
<text></text>
</note>
</notes>
</article>
</articles>
i have to do this query (sql speaking :) ):
SELECT article WHERE note.code=XXX AND note.text CONTAINS YYY
how can i do that in php?

You use Xpath the query language for xml. W3School have a nice tutorial here: http://www.w3schools.com/XPath/
And to use SimpleXML is simple :P:
$xml = new SimpleXMLElement($xmlstring);
$result = $xml->xpath('/articles/article[code=XXX] and /articles/article[text contains(YYY)]');
foreach ($result as $node)
{
//Do stuff
}

If you use SimpleXML you have to iterate over all childrens and then recursive over their children. Look at DOMDocument and getElementsByTagName method.
I think, it is what you are looking for.
http://www.php.net/manual/en/class.domdocument.php
http://www.php.net/manual/en/domdocument.getelementsbytagname.php

Related

Prepending raw XML using PHP's SimpleXML

Given a base $xml and a file containing a <something> tag with attributes, children and children of its children, I would like to append it as first child and all of its children as raw XML.
Original XML:
<root>
<people>
<person>
<name>John Doe</name>
<age>47</age>
</person>
<person>
<name>James Johnson</name>
<age>13</age>
</person>
</people>
</root>
XML in file:
<something someval="x" otherthing="y">
<child attr="val" ..> { some children and values ... }</child>
<child attr="val2" ..> { some children and values ... }</child>
...
</something>
Result XML:
<root>
<something someval="x" otherthing="y">
<child attr="val" ..> { some children and values ... }</child>
<child attr="val2" ..> { some children and values ... }</child>
...
</something>
<people>
<person>
<name>John Doe</name>
<age>47</age>
</person>
<person>
<name>James Johnson</name>
<age>13</age>
</person>
</people>
</root>
This tag would contain several children both direct and recursively, so it would not be practical to build the XML via the SimpleXML operations. Besides, keeping it in a file would result in lower maintenance costs.
Technically it would simply be prepending one child. The problem is that this child would have other children and so on.
On the PHP addChild page there's a comment that says:
$x = new SimpleXMLElement('<root name="toplevel"></root>');
$f1 = new SimpleXMLElement('<child pos="1">alpha</child>');
$x->{$f1->getName()} = $f1; // adds $f1 to $x
However, this does not seem to treat my XML as raw XML therefore causing < and > escaped tags to appear. Several warnings concerning namespaces seem to appear as well.
I suppose I could do a quick replace of such tags but I am not sure whether it could cause future problems and it certainly does not feel right.
Manually hacking the XML is not an option and neither is adding children one by one. Choosing a different library could be.
Any clues on how to get this working?
Thanks!
I'm really not sure if that will work. Try this or downvote this, but I hope it helps. Using DOMDocument (Reference)
<?php
$xml = new DOMDocument();
$xml->loadHTML($yourOriginalXML);
$newNode = DOMDocument::createElement($someXMLtoPrepend);
$nodeRoot = $xml->getElementsByTagName('root')->item(0);
$nodeOriginal = $xml->getElementsByTagName('people')->item(0);
$nodeRoot->insertBefore($newNode,$nodeOriginal);
$finalXmlAsString = $xml->saveXML();
?>
Sometimes UTF-8 can make problems, then try this:
<?php
$xml = new DOMDocument();
$xml->loadHTML(mb_convert_encoding($yourOriginalXML, 'HTML-ENTITIES', 'UTF-8'));
$newNode = DOMDocument::createElement(mb_convert_encoding($someXMLtoPrepend, 'HTML-ENTITIES', 'UTF-8'));
$nodeRoot = $xml->getElementsByTagName('root')->item(0);
$nodeOriginal = $xml->getElementsByTagName('people')->item(0);
$nodeRoot->insertBefore($newNode,$nodeOriginal);
$finalXmlAsString = $xml->saveXML();
?>

How to extract the content of <uri></uri> in a XML document?

I have a document that it's structure is like below.
There are a lot of <entry>. My question is how can I output the <uri> of each entry? And another question, how can I output only the USERNAME?
This is the file I want to get the usernames http://search.twitter.com/search.atom?q=yankees
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns:google="http://base.google.com/ns/1.0" xml:lang="en-US" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns="http://www.w3.org/2005/Atom" xmlns:twitter="http://api.twitter.com/" xmlns:georss="http://www.georss.org/georss">
<entry>
<author>
<name></name>
<uri>http://twitter.com/USERNAME</uri>
</author>
</entry>
<?php
$xml = new DOMDocument;
// link to ur file
$xml->load('');
foreach ($xml->getElementsByTagName('entry') as $product )
{
$append = array();
foreach($product->getElementsByTagName('uri') as $name ) {
// Stick $name onto the array
$append[] = $name;
}
}
$result = $xml->saveXML();
print_r(str_replace('http://twitter.com/','',$result));
?>
You can use Xpath queries
http://www.php.net/manual/en/simplexmlelement.xpath.php
or
http://php.net/manual/en/domxpath.query.php
You should use SimpleXML some kind of a loop which goes trough all the s.
(foreach($xml->entry as $entry) loop should work fine, I think.)
And for the second: if it is always http://twitter.com/USERNAME, simply count the prefix's length than use a substr.
Resources to use: substr, SimpleXML, SimpleXML

PHP: passing an xml node to function

i'm trying to pass an xml node to a function but can't figure out how - here's my xml markup:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<root>
<form>
<item>
<id>frm1</id>
<dbID>1</dbID>
<visible>1</visible>
</item>
</form>
<form>
<item>
<id>frm2</id>
<dbID>2</dbID>
<visible>1</visible>
</item>
</form>
</root>
when setting up a foreach loop - how's the syntax to iterate through the xml and passing the whole node to a function?
i've tried something like:
foreach($xml as $ctlXML => $value)
{
$ctl = generateCTL($ctlXML);
}
but it doesn't work as it should.
thanks
If you are using SimpleXML it is simple as
$xml = simplexml_load_file($path_to_file);
foreach($xml->form as $form){
$ctl = generateCTL($form->item);
}
Be careful - $form->item is an object

Insert an xml element from an xml doc to an other xml document

Let's say I have to xml documents:
<first_root>
<element1/>
<element2>
<embedded_element/>
</element2>
</first_root>
and
<foo>
<bar/>
</foo>
How can I put this second xml doc into the first one, using php and DomDocument or SimpleXML?
I want it to look like something like this:
<first_root>
<element1/>
<element2>
<foo>
<bar/>
</foo>
<embedded_element/>
</element2>
</first_root>
You can do it using DOMDocument:
<?php
$aDoc = DOMDocument::loadXML('<?xml version="1.0" encoding="UTF-8" ?>
<first_root>
<element1/>
<element2>
<embedded_element/>
</element2>
</first_root>');
$bDoc = DOMDocument::loadXML('<?xml version="1.0" encoding="UTF-8" ?>
<foo>
<bar/>
</foo>');
$aEmbeddedElement = $aDoc->getElementsByTagName('embedded_element')->item(0);
$bFoo = $bDoc->documentElement;
$aImportedFoo = $aDoc->importNode($bFoo,true);
$aEmbeddedElement->insertBefore($aImportedFoo);
echo $aDoc->saveXML();
?>
Here I imported the XML into DOMDocuments, then I picked up the first embedded_element occurrence and foo node. After you have to import deeply foo into the first document. Now you can insert foo before embedded_element.
Obviously this is only the happy case...
Documentation: DOM
With SimpleXML you can accomplish this by building a third document based on the first two because you can't append SimpleXMLElements into others. (Or maybe you can but there's something I didn't get)

reading xml: can xpath read 2 fields?

I'm using SimpleXMLElement and xpath to try and read the <subcategory><name> from the xml at the very bottom. This code works.. but the stuff inside the while loop looks a little messy, and now I also want to get the <subcategory><count> and somehow pair it with its appropriate <subcategory><name>.
$names = $xml->xpath('/theroot/category/subcategories/subcategory/name/');
while(list( , $node) = each($names)) {
echo $node;
}
My question: Is it possible to get this pairing while still using xpath since it looks like it can make the job easier?
<theroot>
<category>
<name>Category 1</name>
<subcategories>
<subcategory>
<name>Subcategory 1.1</name>
<count>18</count>
</subcategory>
<subcategory>
<name>Subcategory 1.2</name>
<count>29</count>
</subcategory>
</subcategories>
</category>
<category>
<name>Category 2</name>
<subcategories>
<subcategory>
<name>Subcategory 2.1</name>
<count>18</count>
</subcategory>
<subcategory>
<name>Subcategory 2.2</name>
<count>29</count>
</subcategory>
</subcategories>
</category>
</theroot>
If you are using SimpleXML, and you know the exact layout, it might be easier to do this:
$subcategories = $xml->xpath('/theroot/category/subcategories/subcategory');
foreach($subcategories as $subcategory){
echo $subcategory->name.'='.$subcategory->count;
}
With XPath, you could ofcourse select all subnodes of subcategory, but pairing them back up could be more trouble then just foregoing xpath for the last node.

Categories