JDOM2 - two Namespaces - java

I am trying to build the following XML structure:
<EDIOrderPackage xmlns="urn:URI" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Version>1.0.0.0</Version>
<Test>true</Test>
</EDIOrderPackage>
I use JDOM2 and don't know how to add 2 Namespaces!
Even if I set only one Namespace the result is not the same as I wish it to be.
If I set the Namespace by root.setNamespace() and use the 2nd one with the prefix i it looks like this:
<i:EDIOrderPackage mlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Version>1.0.0.0</Version>
<Test>true</Test>
<i:/EDIOrderPackage>
So there is an i before the EDIPOrderPackage.
If i dont use a prefix is looks like this:
<EDIOrderPackage xmlns="urn:URI">
<Version xmlns="">1.0.0.0</Version>
<Test xmlns="">true</Test>
</EDIOrderPackage>
If if try to add it as attributes, it throws the error message that I cannot an attribute with the name "xmlns"
So how can I build an XML with JDOM looking like the one above?

The trick is that, with Namespaces, you have to specify it correctly for all elements you add.
Additionally, a default Namespace is one that is declared as xmlns="...." and not xmlns:abc="...."
When you use a default namespace, it has no 'prefix' on the elements. So from your example code you have:
The default namespace: xmlns="urn:URI"
The 'i' namespace: xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
You can create these with JDOM as:
Namespace nsDefault = Namespace.getNamespace("urn:URI");
Namespace nsI = Namespace.getNamespace("i", "http://www.w3.org/2001/XMLSchema-instance");
Now, when you create your elements, you have to put them in the right Namespaces:
Element root = new Element("EDIOrderPackage", nsDefault);
Element version = new Element("Version", nsDefault);
Element test = new Element("Test", nsDefault);
root.addNamespaceDeclaration(nsI); // add the i namespace declaration.
root.addContent(version);
root.addContent(test);
If you add the XMLOutputter aspect of things:
Document doc = new Document(root);
XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
xout.output(doc, System.out);
the above code produces the output
<?xml version="1.0" encoding="UTF-8"?>
<EDIOrderPackage xmlns="urn:URI" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Version />
<Test />
</EDIOrderPackage>

Related

Empty default XML namespace xmlns="" attribute being added?

I have simple code where I create root element and append child to it. The problem is that child appends with empty xmlns="" attribute, though I don't expect it. It is a problem only of the first child, and the child of second nesting level is already Ok.
So, the following code -
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.newDocument();
Element rootEl = doc.createElementNS("http://someNamespace.ru", "metamodel");
doc.appendChild(rootEl);
Element groupsEl = doc.createElement("groups");
// This appends with xmlns=""
rootEl.appendChild(groupsEl);
Element groupEl = doc.createElement("group");
// This appends normally
groupsEl.appendChild(groupEl);
Will result to output -
<?xml version="1.0" encoding="UTF-8"?>
<metamodel xmlns="http://someNamespace.ru">
<groups xmlns="">
<group/>
</groups>
</metamodel>
Instead of -
<?xml version="1.0" encoding="UTF-8"?>
<metamodel xmlns="http://someNamespace.ru">
<groups>
<group/>
</groups>
</metamodel>
Note, as I said above, the tag <group> is already free from xmlns.
Your desired markup shows all elements in the default namespace. In order to achieve this, you have to create all elements in the default namespace.
The actual output you're getting has <groups xmlns=""> because groups, and its group child element were created in no namespace:
Element groupsEl = doc.createElement("groups");
Change this to
Element groupsEl = doc.createElementNS("http://someNamespace.ru", "groups");
Similarly, change
Element groupEl = doc.createElement("group");
to
Element groupEl = doc.createElementNS("http://someNamespace.ru","group");

How to remove an specific xml attribute from org.w3c.dom.Document

I have this XML:
<Body xmlns:wsu="http://mynamespace">
<Ticket xmlns="http://othernamespace">
<Customer xlmns="">Robert</Customer>
<Products xmlns="">
<Product>a product</>
</Products>
</Ticket>
<Delivered xmlns="" />
<Payment xlmns="">cash</Payment>
</Body>
I am using Java to read it as a DOM document. I want remove the empty namespace attributes (i.e., xmlns=""). Is there any way to do that?
You need to understand that xmlns is a very special attribute. Basically, the xmlns="" is so that your Customer element is in the "unnamed" namespace, rather than the http://othernamespace namespace (and likewise for other elements which would otherwise inherit a default namespace from their ancestors).
If you want to get rid of the xmlns="", you basically need to put the elements into the appropriate namespace - so it's changing the element name. I don't think the W3C API lets you change the name of an element - you may well need to create a new element with the appropriate namespaced-name, and copy the content. Or if you're responsible for creating the document to start with, just use the right namespace.

Dom4j selectNodes(arg) don't give list of nodes

I am using DOM4j for XML work in java,
my xml is like this:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<abcd name="ab.catalog" xmlns="http://www.xyz.com/pqr" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xyz.com/pqr ./abc.xyz.xsd">
<efg>
......
</efg>
<efg>
.....
</efg>
</abcd>
then,
List<Node>list = document.selectNodes("/abcd/efg");
gets the size of list zero. I feel it's due to namespace specified in the xml.
I tried a lot but cn't get success.
Unprefixed element names in XPath expressions refer to elements that are not in a namespace - they do not take account of the "default" xmlns="..." namespace declared on the document. You need to declare a prefix for the namespace in the XPath engine and then use that prefix in the expression. Here is an example inspired by the DOM4J javadocs:
Map uris = new HashMap();
uris.put("pqr", "http://www.xyz.com/pqr");
XPath xpath = document.createXPath("/pqr:abcd/pqr:efg");
xpath.setNamespaceURIs(uris);
List<Node> nodes = xpath.selectNodes(document);
Modify your code :
List<Node>list = document.selectNodes("//abcd/efg");

How to set namespace only on first tag with XOM?

I am using XOM to build XML documents in Java.
I have created a simple XML document, and I want an XML namespace. But when I set the namespace on the first tag, an empty namespace is set on the childs like xmlns="", how can I get rid of this behaviour? I only want xmlns on the first tag.
I want this XML:
<request xmlns="http://my-namespace">
<type>Test</type>
<data>
<myData>test data</myData>
</data>
</request>
But this is the XML document output from XOM
<request xmlns="http://my-namespace">
<type xmlns="">Test</type>
<data xmlns="">
<myData>test data</myData>
</data>
</request>
This is my Java XOM code:
String namespace = "http://my-namespace";
Element request = new Element("request", namespace);
Element type = new Element("type");
type.appendChild("Test");
request.appendChild(type);
Element data = new Element("data");
request.appendChild(data);
Element myData = new Element("myData");
myData.appendChild("test data");
data.appendChild(myData);
Document doc = new Document(request);
doc.toXML();
This works for me. However, I'm a bit puzzled as to why the Element objects don't inherit the namespace of their parents, though. (Not an XML nor XOM expert)
Code:
String namespace = "http://my-namespace";
Element request = new Element("request", namespace);
Element type = new Element("type", namespace);
type.appendChild("Test");
request.appendChild(type);
Element data = new Element("data", namespace);
request.appendChild(data);
Element myData = new Element("myData", namespace);
myData.appendChild("test data");
data.appendChild(myData);
Document doc = new Document(request);
System.out.println(doc.toXML());
Output:
<?xml version="1.0"?>
<request xmlns="http://my-namespace">
<type>Test</type>
<data>
<myData>test data</myData>
</data>
</request>
I ran into the same problem, and Google lead me here.
#Michael - That's what it says in the javadoc, yes, but unfortunately, that's not how it works when you implement it. The child elements will continue to get blank xmlns attributes unless you do Catchwa's implementation.
Catchwa's implementation works just fine. Only the element I tell it to have a namespace, has a namespace. All empty xmlns attributes are gone. It's strange.
Is it a bug? I can't seem to figure that part out. Or is it just the way XOM works?
Don't confuse namespaces and namespace declarations. The namespace is an intrinsic property of each element. The namespace declaration is the `xmlns' attribute. They are not the same thing, although they are connected. When you create an element, you set its namespace, not its namespace declaration.
In the XOM data model namespaces are not attributes. They are an intrinsic property of the element itself. There is no rule in XML that requires children of an element to be in the same namespace as the parent. Indeed theoretically every element in the document could be in a different namespace.
In XOM you specify the namespace of an element or attribute at the same time you specify the local name. When you create an element, the element initially has no parent so there's no way for XOM to default to giving the element the same namespace as its parent, even if that's what was wanted (and it's not).
When the document is serialized the namespaces are represented by xmlns and xmlns:*prefix* attributes. XOM figures out where to put these elements to match the namespaces you've assigned to each element. Just specify the namespace you want for each element in your code, and let XOM figure out where to put the namespace declarations.
In XOM you can add a namespace declaration to the root element.
Here's a short example with three different namespaces:
final String NS_XLINK = "http://www.w3.org/1999/xlink";
final String NS_OTHER = "http://other.com";
Element root = new Element("root", "http://root.com");
root.addNamespaceDeclaration("xlink", NS_XLINK);
root.addNamespaceDeclaration("other", NS_OTHER);
root.addAttribute(new Attribute("xlink:href", NS_XLINK, "http://somewhere.com"));
root.appendChild(new Element("other:alien", NS_OTHER));
Document doc = new Document(root);
System.out.println(doc.toXML());
which produces this result (with additional line breaks inserted for readability):
<?xml version="1.0"?>
<root
xmlns="http://root.com"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:other="http://other.com"
xlink:href="http://somewhere.com">
<other:alien />
</root>

How do I select something with a blank namespace with Jaxen?

I have the following xml:
<config xmlns="http://www.someurl.com">
<product>
<brand>
<content />
</brand>
</product>
</config>
I'm reading it nicely into JDOM.
However, when I try to use Jaxen to grab the contents, I can't seem to get anything.
Here's an example of what doesn't seem to work:
XPath xpath = new JDOMXPath("config");
SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
namespaceContext.addNamespace("", "http://www.someurl.com");
xpath.setNamespaceContext(namespaceContext);
assert xpath.selectNodes(document).size() > 0 : "should find more than 0";
This assertion always fails.
What am I doing wrong?
You have to assign a prefix. Make that call addNamespace("hopfrog", "http://...");
Then make the XPath ("hopfrog:config");
Keep in mind that the prefixes in XML aren't part of the real data model. The real data model assigns a URL, possibly blank, to each element and attribute. You can use any prefix you want in XPath so long as it's bound to the right URL. Since the URL you want it blank, you bind a prefix to 'blank'.

Categories

Resources