I'm attempting to use QXmlQuery to execute an XQuery expression against a document with a declared default namespace.
For discussion:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://namespace.com/ns1">
<node1 attr1="hi"/>
</root>
Now, I have the following to open and query against the document:
QFile temp("my.xml");
temp.open(QIODevice::ReadOnly | QIODevice::Text);
QXmlQuery query;
query.setFocus(&temp);
QXmlResultItems items;
query.setQuery("/root");
query.evaluateTo(&items);
In running this, 'items' never has data in it, since the document is namespaced. Of course, if I remove the default namespace declaration, 'items' does have the correct data, but I don't have that luxury.
I've tried changing the query to: "/prefix:root", and Qt barks a warning like:
No namespace binding exists for the prefix prefix in prefix:root
So namespace binding does exist! But where? I see QXmlNamePool, but it has no mutator methods. I can create a QXmlName with the pool from the query ala:
QXmlName name(query.namePool(), "prefix", "http://namespace.com/ns1");
But it doesn't change anything. I'm at a loss, other toolkits I have used have simple methods to bind prefixes to namespace URIs.
I believe if you would change your query to
...
QXmlResultItems items;
query.setQuery("declare default element namespace \"http://namespace.com/ns1\"; /root");
...
it should return the data.
hope this helps, regards
Related
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.
Given a valid entry in the DTD of a document:
<!ATTLIST name
id CDATA #IMPLIED
attribute ENTITY #IMPLIED >
How can I get the type of an attribute during xslt transformation, given the name of the attribute and the node?
For example name/#id = 'CDATA'
and name/#attribute = 'ENTITY'
Thanks in advance!
This information is not part of the Xpath data model and isn't reported by the XML parser to XSLT (in fact you can't in general be sure the parser reads the DTD at all)
If you suspect an attribute is of type ENTITY then you can use unparsed-entity-uri(#name) XPath function added by XSLT 1 and if you get anything other than the empty string there was an unparsed entity of that name (whether or not that attribute was declared to be of ENTITY type)
I found out that using Xerxes and Xalan allows a pretty simple implementation for this problem.
First of all extend the stylesheet tag as following:
<xsl:stylesheet xmlns:java="http://xml.apache.org/xalan/java" ....
On the attribute processing template:
<xsl:template match="#*" mode="fix-entity-references">
<xsl:param name="is-entity" select="java:com.ovitas.aton.xslt.Util.isEntity(current())"/>
The code of the referenced class:
import org.apache.xerces.dom.DeferredAttrImpl;
import org.apache.xml.dtm.ref.DTMNodeIterator;
public class Util {
public static boolean isEntity(Object o) {
try {
DTMNodeIterator iter = ((DTMNodeIterator) o);
DeferredAttrImpl attrImpl = (DeferredAttrImpl) iter.getRoot();
return attrImpl.getTypeName().equals("ENTITY");
} catch (ClassCastException e) {
e.printStackTrace();
return false;
}
}
}
Naturally referenced jars must be added to classpath.
System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
The code above enables the use of the xalan transformer.
I'll accept the previous upvoted answer, because this solution is obviously based on the use of xalan and xerxes, but I wanted to add this one as well, for future generations. Maybe it will be useful to someone.
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>
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
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.