How to marshal without a namespace?
Asked Answered
A

7

24

I have a fairly large repetitive XML to create using JAXB. Storing the whole object in the memory then do the marshaling takes too much memory. Essentially, my XML looks like this:

<Store>
  <item />
  <item />
  <item />
.....
</Store>

Currently my solution to the problem is to "hard code" the root tag to an output stream, and marshal each of the repetitive element one by one:

aOutputStream.write("<?xml version="1.0"?>")
aOutputStream.write("<Store>")

foreach items as item
  aMarshaller.marshall(item, aOutputStream)
end
aOutputStream.write("</Store>")
aOutputStream.close()

Somehow the JAXB generate the XML like this

 <Store  xmlns="http://stackoverflow.com">
  <item xmlns="http://stackoverflow.com"/>
  <item xmlns="http://stackoverflow.com"/>
  <item xmlns="http://stackoverflow.com"/>
.....
</Store>

Although this is a valid XML, but it just looks ugly, so I'm wondering is there any way to tell the marshaller not to put namespace for the item elements? Or is there better way to use JAXB to serialize to XML chunk by chunk?

Alcheringa answered 12/5, 2010 at 5:2 Comment(2)
Actually your implementation and suggested output do not match. You are writing the root tag yourself, why is a namespace in the output on the root element.Warp
Ahh good catch. Because I actually use JAXB to "hard code" the root element as well. So what I did was I create a empty Root object, marshal it to a String, then parse the String to extract the root tags. So if JAXB does not generate namespace for root tag then I'm doomed.Alcheringa
M
12

The following did the trick for me:

         XMLStreamWriter writer = ...
         writer.setNamespaceContext(new NamespaceContext() {
            public Iterator getPrefixes(String namespaceURI) {
                return null;
            }

            public String getPrefix(String namespaceURI) {
                return "";
            }

            public String getNamespaceURI(String prefix) {
                return null;
            }
        });
Mongoose answered 8/4, 2011 at 15:8 Comment(1)
#17223402 helped mePopovich
T
13

Check your package-info.java (in the package where your jaxb-annotated classes are). There is the namespace attribute of @XmlSchema there.

Also, there is a namespace attribute in the @XmlRootElement annotation.

Theophany answered 12/5, 2010 at 5:42 Comment(3)
Is there a way to specify in the binding file not to put namespace in my package-info.java and only put the namespace in @XmlRootElement?Alcheringa
you can override it in @XmlRootElement, but as far as I understand, you want it removed completely.Theophany
I tried adding the -npa but it wont work on jaxb2-maven-plugin for some reason.I just want to make the namespace attribute as "" in the package-info.java which is auto generated. My @XmlRootElement has namespace="" but still when it is marshalled it gets the namespace which is present in package-info.java. Complete details here : #15796563Whiz
M
12

The following did the trick for me:

         XMLStreamWriter writer = ...
         writer.setNamespaceContext(new NamespaceContext() {
            public Iterator getPrefixes(String namespaceURI) {
                return null;
            }

            public String getPrefix(String namespaceURI) {
                return "";
            }

            public String getNamespaceURI(String prefix) {
                return null;
            }
        });
Mongoose answered 8/4, 2011 at 15:8 Comment(1)
#17223402 helped mePopovich
T
12

I've tried all solutions provided as answers here and none of them worked for my environment. My current requirements are:

  1. jdk1.6.0_45
  2. JAXB annotated classes are generated upon every rebuild, so changing them is not an option.

I'd like to share with you the results my experiments with solutions I've found on stackoverflow.

Custom NamespaceContext link

Simple and elegant solution, but in my environment I have an exception with the following stacktrace:

javax.xml.stream.XMLStreamException: Trying to write END_DOCUMENT when document has no root (ie. trying to output empty document).

at com.ctc.wstx.sw.BaseStreamWriter.throwOutputError(BaseStreamWriter.java:1473)
at com.ctc.wstx.sw.BaseStreamWriter.reportNwfStructure(BaseStreamWriter.java:1502)
at com.ctc.wstx.sw.BaseStreamWriter.finishDocument(BaseStreamWriter.java:1663)
at com.ctc.wstx.sw.BaseStreamWriter.close(BaseStreamWriter.java:288)
at MyDataConverter.marshal(MyDataConverter.java:53)

I got stuck trying to figure out why this exception occurs and decided to try out something else.

Modification of package-info.java link

The simplest solution I've found. It generally works, but this file is generated upon every build. That's why I have to find another solution.

Schema modification link

Works as described but doesn't solve my problem. I still have a namespace in root element.

DelegatingXMLStreamWriter link

I've also tried solutions mentioned there, but I had a strange assertion in com.sun.xml.bind.v2.runtime.output.NamespaceContextImpl (method declareNsUri) which I've failed to defeat.

My solution

While researching the issue with assertion I had to implement my own version of XMLStreamWriter based on DelegatingXMLStreamWriter.java

public class NamespaceStrippingXMLStreamWriter extends DelegatingXMLStreamWriter {

  public NamespaceStrippingXMLStreamWriter(XMLStreamWriter xmlWriter) throws XMLStreamException {
    super(xmlWriter);
  }

  @Override
  public void writeNamespace(String prefix, String uri) throws XMLStreamException {
    // intentionally doing nothing
  }

  @Override
  public void writeDefaultNamespace(String uri) throws XMLStreamException {
    // intentionally doing nothing
  }

  @Override
  public void writeStartElement(String prefix, String local, String uri) throws XMLStreamException {
    super.writeStartElement(null, local, null);
  }

  @Override
  public void writeStartElement(String uri, String local) throws XMLStreamException {
    super.writeStartElement(null, local);
  }

  @Override
  public void writeEmptyElement(String uri, String local) throws XMLStreamException {
    super.writeEmptyElement(null, local);
  }

  @Override
  public void writeEmptyElement(String prefix, String local, String uri) throws XMLStreamException {
    super.writeEmptyElement(null, local, null);
  }

  @Override
  public void writeAttribute(String prefix, String uri, String local, String value) throws XMLStreamException {
    super.writeAttribute(null, null, local, value);
  }

  @Override
  public void writeAttribute(String uri, String local, String value) throws XMLStreamException {
    super.writeAttribute(null, local, value);
  }
}

The main idea is to avoid passing namespace information to the underlying XMLStreamWriter. Hope this will help you to save some time solving similar problem.

PS. It's not necessary to extend DelegatingXMLStreamWriter in your code. I've done this to show which methods need changing.

Talent answered 29/6, 2016 at 9:53 Comment(0)
E
7

There is a very simple way to get rid of namespace prefixes in your case: just set the attribute elementFormDefault to unqualified in your schema, like this:

<xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified"
       xmlns:xs="http://www.w3.org/2001/XMLSchema"
       xmlns:your="http://www.stackoverflow.com/your/namespace">

You will get the namespace prefix only in the first tag:

<ns1:your xmlns:ns1="http://www.stackoverflow.com/your/namespace">

I hope this helps.

Regards Pawel Procaj

Enfeoff answered 10/11, 2011 at 10:41 Comment(1)
This works great but is there a way to get rid of the namespace in the first(root) tag as well?Whiz
P
2

For me, simply calling xmlStreamWriter.setDefaultNamespace("") solved the issue.

One more thing you have to care in order to remove the namespace prefix from the output is that everywhere you have @XmlElement ensure it does not include the namespace property like @XmlElement(name="", namespace"http://..."); otherwise, none of solutions will work.

Plumate answered 29/4, 2015 at 13:57 Comment(0)
W
0

If you don't specifiy a namespace JaxB will not write one.

Yout could use Stax on a Stream, if your strcuture is not to complicated.

Warp answered 12/5, 2010 at 5:35 Comment(1)
but the fact is I need a namespace, but just at the root element level.Alcheringa
V
-3

This works for me:

marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "");

Voltmeter answered 31/7, 2015 at 15:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.