JAXB 和命名空间相关问题

JAXB and namespaces related issue

编组 JAXB class 后,我有以下 XML:

<?xml version="1.0" encoding="UTF-8"?>
<foo:Object xsi:schemaLocation="http://foo.com/ http://foo.com/foo.xsd" 
xmlns:ns0="http://lipsum.com/bar" xmlns:foo="http://foo.com/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <foo:Some attr1="601"/>
   <foo:Others>
      <bar:Another xsi:schemaLocation="http://lipsum.com/bar 
      http://lipsum.com/bar.xsd" xmlns:bar="http://lipsum.com/bar">
         <bar:SomeOther attr2="01"/>
      </bar:Another>
  </foo:Others>
</foo:Object>

jaxb class 中的 元素声明为:

    @XmlAnyElement(lax = true)
    @XmlElementRefs({
         @XmlElementRef(name="Another", type=Another.class, required=false)
    })
    protected List<Object> any;

它可能包含数量未知的其他元素,这些元素具有自己的命名空间。

问题:

当我编组 Some.class 对象时,jaxb 将 Another.class 的名称空间作为 ns0 放入根元素中,因为我从另一个方法中将 编组为 Element他们的命名空间包括在内我不需要它再次进入根元素。

这是一个问题,因为 不是必需的,所以如果我用空列表编组 Some.class 对象,我将始终拥有 xmlns:ns0.

我需要 @XmlElementRefs 和 @XmlElementRef 注释,因为我需要从 json 转换为 XML 并且 Jackson 需要知道 "any" 列表可能具有的类型。

我如何告诉 JAXB Oracle/Moxy 实现:

1.- Ignore the namespaces from @XmlElementRef classes during the marshalling.
2.- Remove the not used namespaces aka NS[0-9] prefixes from the root element.

如有任何帮助,我们将不胜感激。

为了以防万一有人需要这个,我有办法删除不需要的名称空间,技巧由 XMLStreamWriter

提供

步骤 1.- 创建一个 WrapperXMLStreamWriter class 来包装 XMLStreamWriter。

public class WrapperXMLStreamWriter implements XMLStreamWriter {
    private final XMLStreamWriter writer;

    public WrapperXMLStreamWriter(XMLStreamWriter writer) {
        this.writer = writer;
    }

    /* (non-Javadoc)
     * @see javax.xml.stream.XMLStreamWriter#writeStartElement(java.lang.String)
     */
    @Override
    public void writeStartElement(String localName) throws XMLStreamException {
        // for each overloaded method call to writer do the method
        writer.writeStartElement(localName);
    }

     /* (non-Javadoc)
     * @see javax.xml.stream.XMLStreamWriter#writeNamespace(java.lang.String, java.lang.String)
     */
    @Override
    public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
        // Here is the trick
        if(!prefix.startsWith("ns")){
            writer.writeNamespace(prefix, namespaceURI);
        }
    }

    ...
}

步骤 2.- 像往常一样创建编组器

Map<String,String> prefixes = new HashMap<String, String>();

// 
prefixes.put("http://www.w3.org/2001/XMLSchema-instance","xsi");
prefixes.put("http://foo.com/", "foo");

Marshaller marshaller =  AppContextTool.getInstance().getContextForFoo().createMarshaller();

// 
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapperImpl(prefixes));
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://foo.com/ http://foo.com/foo.xsd");

3.- 使用第一步给定的 XMLStreamWriter 编组 Foo 实例

Foo foo = new Foo();

ByteArrayOutputStream xml= new ByteArrayOutputStream();
try {
    XMLStreamWriter writer = 
                new WrapperXMLStreamWriter((XMLStreamWriter) XMLOutputFactory.newInstance().createXMLStreamWriter(xml, "UTF-8"));

    marshaller.marshal(foo, writer);
} catch (XMLStreamException | FactoryConfigurationError e) {
    e.printStackTrace();
}

4.- 结果:

<?xml version="1.0" encoding="UTF-8"?>
<foo:Object xsi:schemaLocation="http://foo.com/ http://foo.com/foo.xsd" 
 xmlns:foo="http://foo.com/" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <foo:Some attr1="601"/>
        <foo:Others>
            <bar:Another xsi:schemaLocation="http://lipsum.com/bar 
  http://lipsum.com/bar.xsd" xmlns:bar="http://lipsum.com/bar">
          <bar:SomeOther attr2="01"/>
       </bar:Another>
  </foo:Others>
  </foo:Object>

没有更多的 NS 名称空间,希望这对某人有所帮助。