The same Namespace in Child and Sub Child (JDOM2) - java

I need set a namespace in a child and in its child too, but, when I attribute the same namespace, the sub child comes with no namespace.
I need something like that:
<?xml version="1.0" encoding="UTF-8"?>
<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="2.00">
<NFe xmlns="http://www.portalfiscal.inf.br/nfe">
<infNFe versao="2.00" Id="NFe35120810609770000190550010000011151000011155">
...
But my code is generating only this:
<?xml version="1.0" encoding="UTF-8"?>
<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="2.00">
<NFe>
<infNFe versao="2.00" Id="NFe35120810609770000190550010000011151000011155">
...
The code that generates this part of the XML is:
Document doc = new Document();
Namespace portal = Namespace.getNamespace( "http://www.portalfiscal.inf.br/nfe" );
Element tagNfeProc = new Element( "nfeProc", portal );
tagNfeProc.setAttribute( "versao", "2.00" );
Element tagNFe = new Element( "NFe", portal );
...
tagNfeProc.getChildren().add( tagNFe );
doc.setRootElement( tagNfeProc );

If you really want to add it, you have to do it manually, use the 'setAttribute' method mentioned before me.
Otherwise:
The 'NFe' tag doesn't require the namespace attribute again, because that namespace is already declared on a higher level (top level in your example), and it will be used (inherited) within the entire block just where you declared it.
After a little search, a brief description about
XML namespaces :)

Related

JAVA XML find node without knowing parent

JAVA & XML
I have an xml document like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<elezione>
<codice>6</codice>
<descrizione>EUROPEE</descrizione>
<data>25 MAGGIO 2014</data>
<enti-partecipanti>
<italia>
<circ-europea>
<codice>2</codice>
<nome>II : ITALIA NORD-ORIENTALE</nome>
<regione> ..... </regione>
<regione> ..... </regione>
<regione>
<codice>4</codice>
<nome>TRENTINO-ALTO ADIGE</nome>
<provincia>
<codice>14</codice>
<nome>BOLZANO</nome>
.. Whole load of sub nodes and stuff
</provincia>
<provincia>
<codice>14</codice>
<nome>BOLZANO</nome>
.. Whole load of sub nodes and stuff
</provincia>
..
..
</regione>
<regione> ... </regionr>
</circ-europea>
</italia>
</enti-partecipanti>
</elezione>
I need to start examining from the <regione> node with "codice" = 14
Unfortunately the structure ABOVE the list of "<regione>" nodes changes continuously (the supplier of the xml is pretty CRAZY), but below that node, things are pretty standard.
Currently I'm using classic "DocumentBuilder ... " code.
The main problem is that I start my search for regione starting INSIDE the <elezione> node, and not from the document itself, so I don't know how to use xPath starting from a node instead of a document!
Use a xpath starting with "//".
"//regione" will match all the "regione" nodes.

adding mutiple namespace for a element in xml file using dom4j

The XML file which need to generate:
<?xml version="1.0" encoding="UTF-8" ?>
<wrapper:MMSRMessage xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wrapper="urn:iso:std:iso:20022:tech:xsd:head.003.001.01" xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:head.003.001.01 MMSR_head.003.001.01_Wrapper.xsd">
<header:AppHdr xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:header="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
<header:Fr>
...
</header:Fr>
</header:AppHdr>
</wrapper:MMSRMessage>
Two namespaces were added for the root element "wrapper:MMSRMessage",It has no problem.
The following is the Java code for it:
Document document = DocumentHelper.createDocument();
Element wrapper = document.addElement("wrapper:MMSRMessage");
wrapper.addNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
.addNamespace("wrapper", "urn:iso:std:iso:20022:tech:xsd:head.003.001.01")
.addAttribute("xsi:schemaLocation", "urn:iso:std:iso:20022:tech:xsd:head.003.001.01 MMSR_head.003.001.01_Wrapper.xsd");
However, when I add two namespaces for element "header:AppHdr", I get the error message:
Exception in thread "main" org.dom4j.IllegalAddException: No such namespace prefix
using java code:
Element headerApp = wrapper.addElement("header:AppHdr");
headerApp.addNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
.addNamespace("header", "urn:iso:std:iso:20022:tech:xsd:head.001.001.01");
I also have tried so:
Element headerApp = wrapper.addElement("header:AppHdr","urn:iso:std:iso:20022:tech:xsd:head.001.001.01")
.addNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
in this way the error does not occur, but the namespace "xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" can not be added for the element "header:AppHdr".
That's my first question at Stackoverflow. I hope I can get an answer hier :-)
DOM4J generally offers too many ways to skin the cat. In this area, the confusion is increased because Document#addElement(String, String) and Element#addElement(String, String) do very different validations: In the first case you can add an element with a qualified name without having the prefix bound to a namespace and the element ends up having no namespace (this is a bug). In the second case you must have the prefix bound (correct).
All in all, I reccomend not using qualified element and attribute names (prefix:local-name) if you can avoid it. Instead, strictly separate the local name of the element or attribute and use properly declared Namespace and QName constructs. In your case:
Document document = DocumentHelper.createDocument();
Namespace xsi = Namespace.get("xsi", "http://www.w3.org/2001/XMLSchema-instance");
Namespace wrapper = Namespace.get("wrapper", "urn:iso:std:iso:20022:tech:xsd:head.003.001.01");
Namespace header = Namespace.get("header", "urn:iso:std:iso:20022:tech:xsd:head.001.001.01");
Element wrapperElement = document
.addElement(new QName("MMSRMessage", wrapper))
.addAttribute(new QName("schemaLocation", xsi), "urn:iso:std:iso:20022:tech:xsd:head.003.001.01 MMSR_head.003.001.01_Wrapper.xsd");
Element headerApp = wrapperElement.addElement(new QName("AppHdr", header));
headerApp.addElement(new QName("Fr", header));

Xpath and namespace, select node iterator

I have this kind of XML:
<?xml version="1.0" encoding="UTF-8"?>
<documentAnswer xmlns="http://schemas.pkh.hr/doc/2013/documents/rda_30" domainName="rda" domainVersion="3.0">
<answerTimestamp>2013-08-21T13:35:25.894</answerTimestamp>
<correct>
<docId>RDA2_29F81D27-1409BE49E2E-7FF8</docId>
<attachments>
<attachment>
<format>application/pdf</foraat>
<generatedType>StampanNaBlanko</generatedType>
<encodedPdf>JVBERiYKJSVFT0YK</encodedPdf>
</attachment>
</attachments>
</correct>
Those attachment tags can be one or more. I am trying to get NodeIterator of attachment tags in java using
XPathAPI.selectNodeIterator(node,
"/documentAnswer/correct/attachments/attachment")
and then iterate, but I am not succeeding. I am guessing that problem is in xpath and that it is related to namespace, but don't know how to solve it. I tried with this kind of xpath but no success:
XPathAPI.selectNodeIterator(node,
"/rda:documentAnswer/correct/attachments/attachment", "rda",
"http://schemas.pkh.hr/doc/2013/documents/rda_30")
/rda:documentAnswer/correct/attachments/attachment
Here you are assigning the rda namespace only to the root element, but it is declared in the XML as the default namespace. Therefore, all your elements are in that namespace. You must use
/rda:documentAnswer/rda:correct/rda:attachments/rda:attachment
Unfortunately, the XPath standard does not support the declaration of a default namespace.
3 kind of approach :
A-Embed namespace for query QNames and not only local-names()
with corrected header :
<ns0:documentAnswer xmlns:ns0="http://schemas.pkh.hr/doc/2013/documents/rda_30" domainName="rda" domainVersion="3.0">
xpath
/ns0:documentAnswer
B-Query only local-names with local-name() function
/*[local-name()="documentAnswer"]
C-Query local-names and namespaces (querying QNames)
/*[local-name()="documentAnswer" and namespace-uri()='http://schemas.pkh.hr/doc/2013/documents/rda_30']
see http://nealwalters.blogspot.fr/2005/01/common-xpath-examples-questions-issues.html
If you prefer you can get it ignoring the namespaces this way:
/*:documentAnswer/*:correct/*:attachments/*:attachment

Groovy: how to parse xml and preserve namespaces and schemaLocations

I'm trying to use groovy to simply add a node to a at a particular location. My source schema looks like this
<s1:RootNode
xmlns:s1="http://localhost/s1schema"
xmlns:s2="http://localhost/s2schema"
xsi:schemaLocation="http://localhost/s1schema s1schema.xsd
http://localhost/s2schema s2schema.xsd">
<s1:aParentNode>
<s2:targetNode>
<s2:childnode1 />
<s2:childnode2 />
<s2:childnode3 />
<s2:childnode4 />
</s2:targetNode>
</s1:aParentNode>
</s1:RootNode>
I'd like to simply add a new child node inline with the other ones to make the output
<s1:RootNode
xmlns:s1="http://localhost/s1schema"
xmlns:s2="http://localhost/s2schema"
xsi:schemaLocation="http://localhost/s1schema s1schema.xsd
http://localhost/s2schema s2schema.xsd">
<s1:aParentNode>
<s2:targetNode>
<s2:childnode1 />
<s2:childnode2 />
<s2:childnode3 />
<s2:childnode4 />
<s2:childnode5 >value</s2:childnode5>
</s2:targetNode>
</s1:aParentNode>
</s1:RootNode>
To do this i have the following simple groovy script
def data = 'value'
def root = new XmlSlurper(false,true).parseText( sourceXML )
root.'aParentNode'.'topNode'.appendNode{
's2:childnode5' data
}
groovy.xml.XmlUtil.serialize(root);
however when i do this the namespaces and schemaLocations that are applied to the root node are being removed. and the namespace, but not the schema location is being added to each of the child nodes.
this is causing validation issues downstream.
How do i simply process this xml. perform no validation and leave the xml as is and add a single node of a namespace i specify?
One note: we process many messages and i won't know in advance the outer most namespace (s1 in the above example) but even with that, i'm really just lookign for a technique that is a "dumber" processing of xml
Thanks!
First, I had to add xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" to define your xsi namespace. Without it I would receive a SAXParseException for the unbound xsi prefix.
Additionally, I consulted this question on successfully appending a namespaced xml node to an existing document.
Finally, we had to utilize the StreamingMarkupBuilder to work around the moving of the namespaces. Bascially, by default the serializer moves the referenced namespaces to the first node that actually uses the namespace. In your case it was moving your s2 namespace attribute to the "targetNode" tag. The following code produces the results you want, but you will still have to know the correct namespaces to use to instantiate the StreamingMarkupBuilder.
def root = new XmlSlurper(false, true).parseText( sourceXML )
def data = '<s2:childnode5 xmlns:s2="http://localhost/s2schema">value</s2:childnode5>'
def xmlFragment = new XmlSlurper(false, true).parseText(data)
root.'aParentNode'.'targetNode'.appendNode(xmlFragment);
def outputBuilder = new StreamingMarkupBuilder()
String result = XmlUtil.serialize(outputBuilder.bind {
mkp.declareNamespace('s1':"http://localhost/s1schema")
mkp.declareNamespace('s2':"http://localhost/s2schema")
mkp.yield root }
)
XMLSlurper (or XMLParser) does not handle namespaces if you set the second parameter of the constructor:
XmlSlurper (boolean validating, boolean namespaceAware)
to false:
def root = new XmlSlurper(false, false).parseText( sourceXML )
Without setting namespaceAware to false, I also faced strange bahavior of the parser. After setting to false, it leaves the XML as is, with no namespace changes.

Reducing code redundancy while creating XML with XOM

I am using XOM as my XML parsing library. And i am using this for creating XML also. Below is the scenario described with example.
Scenario:
Code:
Element root = new Element("atom:entry", "http://www.w3c.org/Atom");
Element city = new Element("info:city", "http://www.myinfo.com/Info");
city.appendChild("My City");
root.appendChild(city);
Document d = new Document(root);
System.out.println(d.toXML());
Generated XML:
<?xml version="1.0"?>
<atom:entry xmlns:atom="http://www.w3c.org/Atom">
<info:city xmlns:info="http://www.myinfo.com/Info">
My City
</info:city>
</atom:entry>
Notice in the XML that here info namespace is added with the node itself. But I need this to be added in root element. like below
<?xml version="1.0"?>
<atom:entry xmlns:atom="http://www.w3c.org/Atom" xmlns:info="http://www.myinfo.com/Info">
<info:city>
My City
</info:city>
</atom:entry>
And to do that, i just need following piece of code
Element root = new Element("atom:entry", "http://www.w3c.org/Atom");
=> root.addNamespaceDeclaration("info", "http://www.myinfo.com/Info");
Element city = new Element("info:city", "http://www.myinfo.com/Info");
... ... ...
Problem is here i had to add http://www.myinfo.com/Info twice. And in my case there are hundreds of namespaces. So there will so too much redendancy. Is there any way to get rid of this redundancy?
No, there is no way to get rid of this redundancy and that's a deliberate decision. In XOM the namespace is a fundamental part of the element itself, not a function of its position in the document.
Of course you could always declare a named constant for the namespace URI.

Categories

Resources