Adding a stylesheet declaration in my xml using Xerces-C - c++

I have an application in c++ using Xerces-C as main xml manipulation library.
I have my DOMDocument* and my parser and I want to set declarations.
I do the following:
parser->setValidationScheme(xercesc::XercesDOMParser::Val_Never);
parser->setDoSchema(false);
parser->setLoadExternalDTD(false);
I want to add:
<?xml-stylesheet type="text/xsl" href="my_xslt.xsl"?>
How can I do it?

You'll need to use the createProcessingInstruction on the DOMDocument
http://xerces.apache.org/xerces-c/apiDocs-3/classDOMDocument.html#ce898787ba20c00c85be63f28a358507
Once you've created it, append it to the DocumentElement.

Here is the code for doing this:
xercesc::DomDocument *doc;
// ... (initialize doc in some way)
auto root = doc->getDocumentElement();
auto stylesheet = doc->createProcessingInstruction
(X("xml-stylesheet"), X("type=\"text/xsl\" href=\"custom.xsl\""));
doc->insertBefore(stylesheet, root);
This way, the stylesheet information appears in the prolog of the document, which is the typical place for it. X() is some function that encodes a C-style string as a Xerces-compatible XMLCh-string.

Related

How to create a xml node using rapidxml

Hi I want to create the following xml file in C++ using rapidxml on Linux.
How to add an element which is of type name.
<wrapit>
<mainNode>
<name>something1</name>
</mainNode>
</wrapit>
what my code generates looks like following which I don't want.
<wrapit>
<mainNode>
<name something1=""/>
</mainNode>
</wrapit>
I could not find much information for this. Few on wordpress but the xml formats are different.
Code snippet
xml_node<>* root = doc.allocate_node(node_element, "mainNode");
doc.append_node(root);
xml_node<>* child = doc.allocate_node(node_element,"name");
child->append_attribute(doc.allocate_attribute("something1"));
root->append_node(child);
ugg....
xml_node<>* child = doc.allocate_node(node_element,"name","something1");
does it.

Add XML contained in string as XML nodes to existing pugixml tree

I have a configuration file saver/loader. In addition to the expected data, there is a <CustomData> node. When saving the node, we'd simply have a std::string _customData and add it to the node, like this:
pugi::xml_document doc;
pugi::xml_node config = doc.append_child("OurConfig");
// save custom data
pugi::xml_node customData = config.append_child("CustomData");
customData.append_child(pugi::node_pcdata).set_value(_customData);
Our _customData was base64 encoded XML. It is provided from another part of the application. It must be a string, since the other part of the application uses different programming language (C#). As you can imagine, that became annoying, because it wasn't human readable. First step to fix this was simply to get rid of base64 in the app that provides _customData. So now we have readable version, which looks like this:
<?xml version="1.0"?>
<OurConfig>
<CustomData><CfgRoot>
<SomeValue name="External setting for foo" value="Foo"/>
<SomeValue name="External setting for bar" value="Bar"/>
</CfgRoot></CustomData>
</OurConfig>
But it could probably improve if the custom data was directly appended to XML tree instead of as string value. How can I append XML string as XML and not as string to pugixml tree?
Ie. the output I'd like:
<?xml version="1.0"?>
<OurConfig>
<CustomData>
<CfgRoot>
<SomeValue name="External setting for foo" value="Foo"/>
<SomeValue name="External setting for bar" value="Bar"/>
</CfgRoot>
</CustomData>
</OurConfig>
In the docs, there are three methods listed. I used the first one, making a convenience function like this:
bool AppendXMLString(pugi::xml_node target, const std::string& srcString)
{
// parse XML string as document
pugi::xml_document doc;
if (!doc.load_buffer(srcString.c_str(), srcString.length()))
return false;
for (pugi::xml_node child = doc.first_child(); child; child = child.next_sibling())
target.append_copy(child);
return true;
}

Multiple XML namespaces in xerces

I need to create XML files which contain multiple namespaces.
I create the root element with a default namespace, and add another
namespace ("otherNS") with setAttribute().
The problem is, that when i insert an element (with createElement()) which is prefixed with "otherNS",
xerces adds an empty namespace attribute. when I use createElementNS() and explicitly state the otherNS URI, xerces adds the full URI attribute.
In my understanding of XML namespaces, both is wrong. (Also the examples in
http://www.w3schools.com/Xml/xml_namespaces.asp do not repeat the namespace attributes in each element).
This is an example output:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<company xmlns="http://default.namespace.org/NS" xmlns:otherNS="http://other.namespace.org/ONS">
<otherNS:product xmlns="">Xerces-C</otherNS:product>
<otherNS:category xmlns:otherNS="http://other.namespace.org/ONS" idea="great">XML Parsing Tools</otherNS:category>
<developedBy xmlns="">Apache Software Foundation</developedBy>
</company>
And this is the code:
DOMDocument* doc = impl->createDocument(
X("http://default.namespace.org/NS"),
X("company"),
0);
DOMElement* rootElem = doc->getDocumentElement();
rootElem->setAttribute(
X("xmlns:otherNS"),
X("http://other.namespace.org/ONS"));
DOMElement* prodElem = doc->createElement(X("otherNS:product"));
rootElem->appendChild(prodElem);
DOMText* prodDataVal = doc->createTextNode(X("Xerces-C"));
prodElem->appendChild(prodDataVal);
DOMElement* catElem = doc->createElementNS(
X("http://other.namespace.org/ONS"),
X("otherNS:category"));
rootElem->appendChild(catElem);
My questions are:
Is my usage of the Xerces API correct? Do I maybe have to add the second namespace differently, it seems that xerces does not recognize it.
Are there maybe any features of the DOMLSSerializer class, which change that behaviour, so far I have not found any.
I got the solution on the Xerces mailing list:
Replace:
rootElem->setAttribute(
X("xmlns:otherNS"),
X("http://other.namespace.org/ONS"));
with:
rootElem->setAttributeNS(X("http://www.w3.org/2000/xmlns/"),
X("xmlns:otherNS"),
X("http://other.namespace.org/ONS"));
The reason: the namespace definition itself must be located in the xmlns namespace, so the setAttributeNS() method has to be used.

Poco library for c++, declare namespace for custom element

I want to create an XML document by building a DOM document from scratch, with syntax like:
AutoPtr<Document> doc = new Document;
AutoPtr<Element> root = doc->createElement("root");
doc->appendChild(root);
AutoPtr<Element> element1 = doc->createElementNS("http://ns1", "ns1:element1");
root->appendChild(element1);
AutoPtr<Element> element2 = doc->createElementNS("http://ns1", "ns1:element2");
root->appendChild(element2);
DOMWriter writer;
writer.setNewLine("\n");
writer.setOptions(XMLWriter::PRETTY_PRINT);
writer.writeNode(std::cout, doc);
But, when I write it, I get next result:
<root>
<ns1:element1 xmlns:ns1="http://ns1"/>
<ns1:element2 xmlns:ns1="http://ns1"/>
</root>
So namespace ns1 declared two times, and I want to declare it inside "root" element.
Is there way to get next representation:
<root xmlns:ns1="http://ns1"/>
<ns1:element1/>
<ns1:element2/>
</root>

Why can't I use xpath to parse nodes in the default namespace?

I'm an XML newbie and I have an XML document (which I can't edit because it comes from somewhere else) but it has a root node like this:
<Configuration xmlns="http://schemas.mycomp.com/product/settings" version="2.0.0">
I'm trying to parse this document with msxml and xpath and I've done it successfully if I remove the xmlns attribute. For some reason, with this xmlns attribute in place, the document won't parse. I've attempted to set the msxml parse to recognise the document using:
m_pXMLDoc->setProperty( _bstr_t(L"AllowDocumentFunction"), _variant_t(true));
m_pXMLDoc->setProperty( _bstr_t(L"AllowXsltScript"), _variant_t(true));
m_pXMLDoc->setProperty( _bstr_t(L"SelectionLanguage"), _variant_t(L"XPath"));
m_pXMLDoc->setProperty( _bstr_t(L"SelectionNamespaces"), _variant_t(L"xmlns='http://schemas.mycomp.com/product/settings'"));
m_pXMLDoc->preserveWhiteSpace = VARIANT_FALSE;
m_pXMLDoc->resolveExternals = VARIANT_TRUE;
m_pXMLDoc->validateOnParse = VARIANT_FALSE;
From reading around it looks like xpath only works on the "no name" namespace and this document sets the default namespace so that it's no longer "no name". Can I set the namespace that xpath uses using MSXML?
From Microsoft : This behaviour is by design ...
See http://support.microsoft.com/kb/288147
Use prefixes with the namespaces when you specify the SelectionNamespaces property