Decode a xml from std::string with tinyXml - tinyxml

Actually, i have a c++ code which decode a xml from a xml file with TinyXML library.
std::string = "xmlFile.xml";
TiXmlDocument doc(xml_name);
bool loadOkay = doc.LoadFile();
if (loadOkay){...}
Where xmlFile.xml
<?xml version="1.0">
<body>
....
</body>
Now I need to decode the same xml, but now I have the xml contents atfunction input.
I have thought it would be something like:
std::string contents = "<?xml version="1.0"> <body> ... </body>";
TiXmlDocument doc(contents);
bool loadOkay = doc.LoadFile();
if (loadOkay){...}
But obviously, this not work so.
How can I solve this?

Try the TiXmlDocument::Parse() method instead of the LoadFile() method. Also take a look at this question.
Can TinyXml load Xml from string instead of file?

Related

How replace DTD path Nokogiri?

I'm opening a XML file with this content:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE relatos PUBLIC "-//SINCODH/DTD relatos 0.97" "relatos.dtd">
<relatos>
</relatos>
Now, I want to replace the DOCTYPE tag for a new dtd:
<!DOCTYPE relatos SYSTEM "test/dummy/public/midtd.dtd">
I'm trying with this, but seems first i need to remove dtd tag existing:
docnoko = Nokogiri::XML(doc)
docnoko.create_internal_subset("relatos", nil, "test/dummy/public/midtd.dtd")
Well, usually Nokogiri makes it really easy to replace nodes or delete them and add something else in, but this requires a bit of a work-around:
require 'nokogiri'
old_doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE relatos PUBLIC "-//SINCODH/DTD relatos 0.97" "relatos.dtd">
<relatos>
<foo />
<bar />
</relatos>
EOT
Create a new document:
new_doc = Nokogiri::XML('<relatos/>')
Which looks like this:
new_doc.to_xml # => "<?xml version=\"1.0\"?>\n<relatos/>\n"
Then add the new DTD:
new_doc.create_internal_subset('relatos', nil, 'test/dummy/public/midtd.dtd')
Then append the nodes from the old document to the new one:
new_doc.at('relatos').children = old_doc.at('relatos').children
Resulting in:
new_doc.to_xml # => "<?xml version=\"1.0\"?>\n<!DOCTYPE relatos SYSTEM \"test/dummy/public/midtd.dtd\">\n<relatos>\n <foo/>\n <bar/>\n</relatos>\n"
Here's the code in one chunk:
require 'nokogiri'
old_doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE relatos PUBLIC "-//SINCODH/DTD relatos 0.97" "relatos.dtd">
<relatos>
<foo />
<bar />
</relatos>
EOT
new_doc = Nokogiri::XML('<relatos/>')
new_doc.create_internal_subset('relatos', nil, 'test/dummy/public/midtd.dtd')
new_doc.at('relatos').children = old_doc.at('relatos').children
You might ask on the Nokogiri-Talk list or their IRC channel as the really smart people hang out there.

SimpleXML (Zend_Config_Xml actually) and foreach : which tag am I iterating?

I'm implementing a little event manager in order to use the Observer pattern. To subscribe my observers to my events, I'm using the following xml file :
<?xml version="1.0" encoding="UTF-8"?>
<configData>
<subscriptions>
<subscription>
<eventName>event_name</eventName>
<class>My_Observer_Class</class>
<function>myFunction</function>
</subscription>
<subscription>
<eventName>other_event_name</eventName>
<class>My_Observer_Otherclass</class>
<function>myOtherFunction</function>
</subscription>
</subscriptions>
</configData>
I'm using a foreach to loop on the subscriptions :
foreach($subscriptions->subscription as $subscription) {
/* using $subscription->eventName etc... */
}
And everything is ok, each $subscription item has it's eventName etc...
But here comes my problem :
<?xml version="1.0" encoding="UTF-8"?>
<configData>
<subscriptions>
<subscription>
<eventName>event_name</eventName>
<class>My_Observer_Class</class>
<function>myFunction</function>
</subscription>
</subscriptions>
</configData>
Here I have only one <subscription> node. And my foreach loops on the subscription children !
To solve this problem, I'd like to know how I can check if the xml file contains several <subscription> tags, or just one...
Any help will be appreciated :)
Edit : Is there a way to use xpath with my Zend_Config_Xml object ?
You can use Xpath.
Please try below code, i have tested it with both of sample XML's you provided.
<?php
$subscriptions = simplexml_load_file('test.xml');
$scTag = $subscriptions->xpath("//subscription");
foreach($scTag as $subscription) {
echo $subscription->eventName;
/* using $subscription->eventName etc... */
}
?>
hope this help !
Just to clarify, this is an issue with Zend_Config_XML which is not present in PHP's native SimpleXML.
Given your second example as $xml, I can run the following and get the word 'subscription' as expected:
$configData = simplexml_load_string($xml);
foreach($configData->subscriptions->subscription as $subscription)
{
echo $subscription->getName();
}

How to remove namespace from xml

I have a XML in following format
<Body xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<TransactionAcknowledgement xmlns="">
<TransactionId>HELLO </TransactionId>
<UserId>MC</UserId>
<SendingPartyType>SE</SendingPartyType>
</TransactionAcknowledgement>
</Body>
I want to user XQuery or XPath expression for it.
Now I want to remove only
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
namespace from xml.
Is there any way to achieve it.
Thanks
Try to use functx:change-element-ns-deep:
let $xml := <Body xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<TransactionAcknowledgement xmlns="">
<TransactionId>HELLO </TransactionId>
<UserId>MC</UserId>
<SendingPartyType>SE</SendingPartyType>
</TransactionAcknowledgement>
</Body>
return functx:change-element-ns-deep($xml, "http://schemas.xmlsoap.org/soap/envelope/", "")
But as said Dimitre Novatchev this function doesn't change namespace of the source xml, it creates a new XML.

YQL Losing HTML Element Attributes?

YQL Console Link
Query:
select * from html where url='http://www.cbs.com/shows/big_brother/video/' and xpath='//div[#id="cbs-video-metadata-wrapper"]/div[#class="cbs-video-share"]/a'
Returns:
<?xml version="1.0" encoding="UTF-8"?>
<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng"
yahoo:count="1" yahoo:created="2011-07-09T23:14:02Z" yahoo:lang="en-US">
<diagnostics>
<publiclyCallable>true</publiclyCallable>
<url execution-time="146" proxy="DEFAULT"><![CDATA[http://www.cbs.com/shows/big_brother/video/]]></url>
<user-time>163</user-time>
<service-time>146</service-time>
<build-version>19262</build-version>
</diagnostics>
<results>
<a class="twitter-share-button" href="http://twitter.com/share"/>
</results>
</query>
Should Return Something Similar To:
<results>
</results>
If I back out the query one level, it totally strips out the element, which I could also use to get the data I need.
We have a new html parser that recognizes custom attributes now.
Add compat="html5" to trigger the new parser.
e.g.:
select * from html where url = "http://mydomain.com" and compat="html5"

Problem with namespace and libxml when i use Xpath

i've got a problem when i'm using libxml with XPath. I want to parse an youtube playlist :
<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://www.w3.org/2005/Atom'
xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/'
xmlns:media='http://search.yahoo.com/mrss/'
xmlns:batch='http://schemas.google.com/gdata/batch'
xmlns:yt='http://gdata.youtube.com/schemas/2007'
xmlns:gd='http://schemas.google.com/g/2005'
gd:etag='W/"Dk8DRn47eCp7ImA9WxRQGEk."'>
<id>tag:youtube,2008:user:andyland74:playlists</id>
<updated>2008-07-21T16:43:25.232Z</updated>
<category scheme='http://schemas.google.com/g/2005#kind'
term='http://gdata.youtube.com/schemas/2007#playlistLink'/>
<title>Playlists of andyland74</title>
<logo>http://www.youtube.com/img/pic_youtubelogo_123x63.gif</logo>
<link rel='related' type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74?v=2'/>
<link rel='alternate' type='text/html'
href='http://www.youtube.com/profile_play_list?user=andyland74'/>
<link rel='http://schemas.google.com/g/2005#feed'
type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists?v=2'/>
<link rel='http://schemas.google.com/g/2005#post'
type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists?v=2'/>
<link rel='http://schemas.google.com/g/2005#batch'
type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists/batch?v=2'/>
<link rel='self' type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists?...'/>
<link rel='service' type='application/atomsvc+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists?alt=...'/>
<author>
<name>andyland74</name>
<uri>http://gdata.youtube.com/feeds/api/users/andyland74</uri>
</author>
<generator version='2.0'
uri='http://gdata.youtube.com/'>YouTube data API</generator>
<openSearch:totalResults>3</openSearch:totalResults>
<openSearch:startIndex>1</openSearch:startIndex>
<openSearch:itemsPerPage>25</openSearch:itemsPerPage>
<entry gd:etag='W/"Dk8DRn47eCp7ImA9WxRQGEk."'>
<id>tag:youtube,2008:user:andyland74:playlist:8BCDD04DE8F771B2</id>
<published>2007-11-04T17:30:27.000-08:00</published>
<updated>2008-07-15T12:33:20.000-07:00</updated>
<app:edited xmlns:app='http://www.w3.org/2007/app'>2008-07-15T12:33:20.000-07:00</app:edited>
<category scheme='http://schemas.google.com/g/2005#kind'
term='http://gdata.youtube.com/schemas/2007#playlistLink'/>
<title>My New Playlist Title</title>
<summary>My new playlist Description</summary>
<content type='application/atom+xml;type=feed'
src='http://gdata.youtube.com/feeds/api/playlists/8BCDD04DE8F771B2?v=2'/>
<link rel='related' type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74?v=2'/>
<link rel='alternate' type='text/html'
href='http://www.youtube.com/view_play_list?p=8BCDD04DE8F771B2'/>
<link rel='self' type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists/8BCDD04DE8F771B2?v=2'/>
<link rel='edit' type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists/8BCDD04DE8F771B2?v=2'/>
<author>
<name>andyland74</name>
<uri>http://gdata.youtube.com/feeds/api/users/andyland74</uri>
</author>
<yt:countHint>9</yt:countHint>
</entry>
</feed>
when i use the following xpath expression "/feed", the xmlXPathEvalExpression say me that i doesnt find.
if i remove all the xmlns attributes of feed it works. How could i make it work even with xmlns attributes ?
i use libxml with objective-C
I ran into a similar issue when trying to use libxml-ruby to parse through xml. From http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/XPath.html:
To find nodes you must define the atom
namespace for libxml. One way to do
this is:
node = doc.find('atom:title', 'atom:http://www.w3.org/2005/Atom')
Alternatively, you can register the
default namespace like this:
doc.root.namespaces.default_prefix = 'atom' node = doc.find('atom:title')
Either way works, but registering makes sense if you're going to be using the methods a lot. Then you can just reference items like 'atom:title'.
I am using the XPathQuery wrapper around xmlXPathEvalExpression which makes it harder to go the xmlXpathRegisterNS route.
If you are querying for the fields directly, you probably do not care about the namespaces - it doesn't matter for my app. So, I just modified the XML before I process it.
NSString *xmlString = [[NSString alloc] initWithData:originalXMLData encoding:NSUTF8StringEncoding];
NSString *modifiedXMLString = [xmlString stringByReplacingOccurrencesOfString:#"xmlns=" withString:#"foobar="];
NSData *modifiedXMLData = [modifiedXMLString dataUsingEncoding:NSUTF8StringEncoding];
Now you can use modifiedXMLData in xmlXPathEvalExpression or PerformXMLXPathQuery if you use XPathQuery.
You didn't post your query code, but it sounds like you aren't registering the namespaces with your XpathContext. Here's the API docs for xmlXPathRegisterNS, I believe it will do what you're looking for. It won't let you register a default namespace, so you'll need to change your XPath expression to /feed:feed or the like.
To use a default namespace just register the namespace xlmns= and then use /xmlns:feed in your query.
After some research, I found the following solution that just works like NSXMLDocument path queries:
when xml documents declare a default namespace without a prefix, like
xmlns="..."
simple xpaths queries fail, like
xpath: /node
that's because xmlXPathEvalExpressionexpects some kind of default namespace prefix but there is none.
One approach is to fix the missing prefix (like GDataXML does) but that requires all xpaths to use this prefix, like
xpath: /__def_ns:node
But this is not how xpath's and NSXMLDocument works.
The following solution (based on a DDXMLNode) goes to the root node and scans for a namesepace without a prefix.
Then all nodes below are being traversed and if they belong to that namespace, it is being removed.
This is just like if there was no namespace in the first place.
- (void)fixNameSpace
{
xmlNodePtr nodePtr = (xmlNodePtr)self->genericPtr;
xmlNsPtr ns = nodePtr->nsDef;
xmlNsPtr defaultNs = NULL;
while(ns != NULL)
{
if (ns->prefix == NULL)
{
defaultNs = ns;
break;
}
ns = ns->next;
}
if (defaultNs)
[self resetDefaultNs:defaultNs];
}
- (void)resetDefaultNs:(xmlNsPtr)defaultNs
{
xmlNodePtr nodePtr = (xmlNodePtr)self->genericPtr;
xmlNsPtr ns = nodePtr->ns;
if (ns && ns == defaultNs)
xmlSetNs(nodePtr, NULL);
for (NSXMLNode* child in self.children)
[child resetDefaultNs:defaultNs];
}

Resources