javaxmlxml-namespacesxom

Generating part of XML with namespaces with XOM


Though the description looks like really long, its actually quite straightforward.

What I need

I have the following xml document

<?xml version="1.0" encoding="UTF-8"?>
<atom:feed xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:atom="http://www.w3.org/2005/Atom" type="application/atom+xml;type=feed">
  <atom:link rel="self" href="http://hostname/thirdparty/playlist"/>
  <atom:id>vuter id</atom:id>
  <atom:title>Untitled</atom:title>
  <opensearch:totalResults>249</opensearch:totalResults>
  <opensearch:startIndex>1</opensearch:startIndex>
  <opensearch:itemsPerPage>249</opensearch:itemsPerPage>
  <atom:entry type="application/atom+xml;type=entry">
    <atom:id>12345678</atom:id>
    <atom:title>Playlist example 1</atom:title>
    <atom:link rel="self" type="application/atom+xml;type=entry" href="http://hostname/thirdparty/playlist/2101211130000011141"/>
    <dcterms:identifier>2101211130000011141</dcterms:identifier>
  </atom:entry>
  <atom:entry type="application/atom+xml;type=entry">
    <atom:id>12345678</atom:id>
    <atom:title>Playlist example 2</atom:title>
    <atom:link rel="self" type="application/atom+xml;type=entry" href="http://hostname/thirdparty/playlist/2101211090000000341"/>
    <dcterms:identifier>2101211090000000341</dcterms:identifier>
  </atom:entry>
</atom:feed>

Notice that the xml is containing basically three namespaces

Now I need to generate another xml document of a single atom:entry node. Like below

<atom:entry type="application/atom+xml;type=entry" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:atom="http://www.w3.org/2005/Atom">
    <atom:id>12345678</atom:id>
    <atom:title>Playlist example 1</atom:title>
    <atom:link rel="self" type="application/atom+xml;type=entry" href="http://hostname/thirdparty/playlist/2101211130000011141"/>
    <dcterms:identifier>2101211130000011141</dcterms:identifier>
</atom:entry>

What Im getting

I am using XOM and so far ive tried with

Element rootElem = new Builder().build(ins).getRootElement();
xc = XPathContext.makeNamespaceContext(rootElem);    
Element firstEntry = (Element) rootElem.query("atom:entry", xc).get(0); 
Document doc = new Document((Element)firstEntry.copy());
System.out.println(doc.toXML());

And Im getting following xml with only one namespace declaration. Like below.

<?xml version="1.0"?>
<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" type="application/atom+xml;type=entry">
    <atom:id>12345678</atom:id>
    <atom:title>Playlist example 1</atom:title>
    <atom:link rel="self" type="application/atom+xml;type=entry" href="http://hostname/thirdparty/playlist/2101211130000011141" />
    <dcterms:identifier xmlns:dcterms="http://purl.org/dc/terms/">2101211130000011141</dcterms:identifier>
</atom:entry>

Problem

Its containning only Atom namespace :( Hence its not a valid XML. Because it has a child node dcterms:identifier whose namespace is missing.

I need help badly to get out of this problem. Looking forward for any help.


Solution

  • There is no a problem. The dcterms namespace is declared where is needed: in the dcterms:identifier tag

    <dcterms:identifier xmlns:dcterms="http://purl.org/dc/terms/">
    

    In fact, the xml you expect and the one you get are the same. The fact that the namespaces are not declare in the same place does not affect the meaning of the xml content.

    =======UPDATE========

    I would advise to solve the real problem, ie the fact that your system does not accept valid xmls (or it does not interpret them correctly). As a fix for your situation try the following piece of code:

    Element rootElem = new Builder().build(ins).getRootElement();
    XPathContext xc = XPathContext.makeNamespaceContext(rootElem);    
    Element firstEntry = (Element) rootElem.query("atom:entry", xc).get(0); 
    Document doc = new Document((Element)firstEntry.copy());
    Element root = doc.getRootElement();
    recursive(root,root);
    
    static void recursive(Element root, Element child){
            root.addNamespaceDeclaration(child.getNamespacePrefix(), child.getNamespaceURI());
            if (child.getChildElements().size()>0){
                int i = child.getChildElements().size();
                for (int k=0;k<i;k++){
                    recursive(root,child.getChildElements().get(k));
                }
            }
        }
    

    Basically the code above goes through all the children, identifies there namespace and adds it to the root as namespace declaration. I have tried it and worked. I hope it will act as a fix for your problem