代码之家  ›  专栏  ›  技术社区  ›  sfussenegger

JAXB:如何避免xmlns:xsi的重复命名空间定义

  •  20
  • sfussenegger  · 技术社区  · 16 年前

    Person 类型的对象 PersonRef 只包含用户的UUID。这个很好用。但是,生成的XML重新声明相同的名称空间( xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" )每次使用时。虽然这通常是好的,只是感觉不对劲。

    下面是我想要实现的一个例子:

    电流:

    <person uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a">
        <relation type="CHILD"> 
            <to xsi:type="personRef" uuid="56a930c0-5499-467f-8263-c2a9f9ecc5a0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/> 
        </relation> 
        <relation type="CHILD"> 
            <to xsi:type="personRef" uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/> 
        </relation>
        <!-- SNIP: some more relations -->
    </person>
    

    <person uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <relation type="CHILD"> 
            <to xsi:type="personRef" uuid="56a930c0-5499-467f-8263-c2a9f9ecc5a0"/> 
        </relation> 
        <relation type="CHILD"> 
            <to xsi:type="personRef" uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a"/> 
        </relation>
        <!-- SNIP: some more relations -->
    </person>
    
    8 回复  |  直到 16 年前
        1
  •  6
  •   Ron Ben    10 年前

    marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapper() {
                    @Override
                    public String[] getPreDeclaredNamespaceUris() {
                        return new String[] { 
                            XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI
                        };
                    }
    
                    @Override
                    public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
                        if (namespaceUri.equals(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI))
                            return "xsi";
                        if (namespaceUri.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI))
                            return "xs";
                        if (namespaceUri.equals(WellKnownNamespace.XML_MIME_URI))
                            return "xmime";
                        return suggestion;
    
                    }
                });
    
        2
  •  17
  •   msp albert muda    16 年前

    那个 但是您可以向根元素添加一个空schemaLocation:

    marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "");
    
        3
  •  9
  •   Bill the Lizard    14 年前

    JAXB customization Namespace mapper issue

       <?xml version="1.0"?>
       <root>
          <ns1:element xmlns:ns1="urn:foo"> ... </ns1:element>
          <ns2:element xmlns:ns2="urn:foo"> ... </ns2:element>
          <ns3:element xmlns:ns3="urn:foo"> ... </ns3:element>
       </root>
    

    JAXB也可以在XML文档的中间声明额外的命名空间,例如当有限定名称时( QName

    问题是,自动生成的名称空间前缀(如ns1、ns2和ns3)对用户不友好——它们通常不能帮助人们理解编组的XML。

    幸运的是,jaxb2.0(或更高版本)提供了一个名为 com.sun.xml.bind.marshaller.NamespacePrefixMapper

    NamespacePrefixMapper 班级。结果,封送处理程序自动生成一个名称空间前缀,在本例中为ns2。

       <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
       <ns2:JustAnElement xmlns:ns2="a">
           <foo>true</foo>
       </ns2:JustAnElement>
    

    避免命名空间重复的配置示例:

    第二次编组由 JAXBSample 程序使用 分类如下:

       NamespacePrefixMapper m = new PreferredMapper();
                   marshal(jc, e, m);
    
       public static class PreferredMapper extends NamespacePrefixMapper {
               @Override
               public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
                   return "mappedNamespace" + namespaceUri;
               }
           }
    

    getPreferredPrefix() 中的方法 PreferredMapper 类返回首选前缀,在本例中, mappedNamespacea 在封送XML的根元素处声明。

       <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
       <mappedNamespacea:JustAnElement xmlns:mappedNamespacea="a">
           <foo>true</foo>
       </mappedNamespacea:JustAnElement>
    
        4
  •  4
  •   Miguel de Melo    15 年前

    <dependency>
                <groupId>com.sun.xml.bind</groupId>
                <artifactId>jaxb-impl</artifactId>
                <version>2.2.2</version>
                <type>jar</type>
                <scope>compile</scope>
            </dependency>
    

    如果您按照上述示例中的定义配置注释,则不需要PreferredMapper。虽然我有一个package-info.jave文件,但有如下混淆:

    @javax.xml.bind.annotation.XmlSchema(
            namespace = "mylovelynamespace1", 
            xmlns = {
                        @javax.xml.bind.annotation.XmlNs(prefix = "myns1", namespaceURI = "mylovelynamespace1"),
                        @javax.xml.bind.annotation.XmlNs(prefix = "myns2", namespaceURI = "mylovelynamespace2")
                    }, 
                    elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
    package com.mylovelycompanyname.package;
    
        5
  •  2
  •   boomz    13 年前

    这是我在网上找到的最好的答案。

    这个 xsi:type 声明很可能是因为 JAXBElement

    如果 ObjectFactory 具有正确的 贾斯贝尔门特 您应该使用它,因为它应该正确地填充 QName 以及类型信息;否则,我将尝试设置 String.class (假设这是 commentTest CommentType.Comment .

    资料来源: http://www.java.net/forum/topic/glassfish/metro-and-jaxb/how-do-i-remove-namespace-declarations-child-elements

    所有者:

        6
  •  2
  •   Amio.io    12 年前

    您只能编写一次名称空间。您将需要XMLStreamWriter的代理类和一个package-info.java。然后在代码中执行以下操作:

    StringWriter stringWriter = new StringWriter();
    XMLStreamWriter writer = new Wrapper((XMLStreamWriter) XMLOutputFactory
                                                                   .newInstance().createXMLStreamWriter(stringWriter));
    JAXBContext jaxbContext = JAXBContext.newInstance(Collection.class);
    Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
    jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
    jaxbMarshaller.marshal(books, writer);
    System.out.println(stringWriter.toString());
    

    代理类(重要方法是“writeNamespace”):

                class WrapperXMLStreamWriter implements XMLStreamWriter {
    
                       private final XMLStreamWriter writer;
    
                       public WrapperXMLStreamWriter(XMLStreamWriter writer) {
                           this.writer = writer;
                       }
    
                         //keeps track of what namespaces were used so that not to 
                         //write them more than once
                       private List<String> namespaces = new ArrayList<String>();
    
                       public void init(){
                           namespaces.clear();
                       }
    
                       public void writeStartElement(String localName) throws XMLStreamException {
                           init();
                           writer.writeStartElement(localName);
    
                       }
    
                       public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
                           init();
                           writer.writeStartElement(namespaceURI, localName);
                       }
    
                       public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
                           init();
                           writer.writeStartElement(prefix, localName, namespaceURI);
                       }
    
                       public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
                           if(namespaces.contains(namespaceURI)){ 
                               return;
                           }
                           namespaces.add(namespaceURI);
                           writer.writeNamespace(prefix, namespaceURI);
                       }
    
        // .. other delegation method, always the same pattern: writer.method() ...
    
    }
    

    package-info.java包:

    @XmlSchema(elementFormDefault=XmlNsForm.QUALIFIED, attributeFormDefault=XmlNsForm.UNQUALIFIED ,
            xmlns = { 
            @XmlNs(namespaceURI = "http://www.w3.org/2001/XMLSchema-instance", prefix = "xsi")})
    package your.package;
    
    import javax.xml.bind.annotation.XmlNs;
    import javax.xml.bind.annotation.XmlNsForm;
    import javax.xml.bind.annotation.XmlSchema;
    
        7
  •  0
  •   java.is.for.desktop    16 年前

    它是XML,因此可以使用DOM或XSLT处理输出,以消除多个名称空间引用。

        8
  •  -1
  •   sschale    10 年前

    nsPrefix 通过执行以下操作进行映射:

    marshaller.setNamespaceMapping("myns","urn:foo");