JAXB命名空間及命名空間前綴處理


本篇介紹下JAXB進階使用,命名空間處理

  • 使用package-info.java添加默認命名空間
    在需要添加命名空間的包下面添加package-info.java文件,然后添加@XmlSchema注解,這樣整個包序列化時就都會自動加上命名空間了
    @XmlSchema(namespace = "http://www.lzrabbit.cn")
    package cn.lzrabbit;
    
    import javax.xml.bind.annotation.XmlSchema;

     

  • 命名空間前綴處理
    相信大名鼎鼎的ns2,nsXX讓很多人非常頭疼類似下面這樣的
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <ns2:classA xmlns:ns2="http://www.lzrabbit.cn">
        <classAId>11</classAId>
        <ClassAName>A1</ClassAName>
        <classB>
            <ClassBId>22</ClassBId>
            <ClassBName>B2</ClassBName>
        </classB>
    </ns2:classA>

    解決方法一(不推薦):
    添加package-info.java添加@XmlSchema注解並設置屬性xmlns

    @XmlSchema( xmlns = { @XmlNs(namespaceURI = "http://www.lzrabbit.cn", prefix = "rabbit"), @XmlNs(namespaceURI = "http://www.cnblogs.com", prefix = "blog")})
    
    package cn.lzrabbit;
    import javax.xml.bind.annotation.XmlSchema;
    import javax.xml.bind.annotation.XmlNs;

    ClassA如下

    package cn.lzrabbit;
    
    import javax.xml.bind.annotation.*;
    
    @XmlRootElement(namespace="http://www.lzrabbit.cn")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class ClassA {
        private int classAId;
        
        @XmlElement(name="ClassAName")
        private String classAName;
    
        private ClassB classB;
    
        public int getClassAId() {
            return classAId;
        }
        public void setClassAId(int classAId) {
            this.classAId = classAId;
        }
    
        public String getClassAName() {
            return classAName;
        }
    
        public void setClassAName(String classAName) {
            this.classAName = classAName;
        }
    
        public ClassB getClassB() {
            return classB;
        }
    
        public void setClassB(ClassB classB) {
            this.classB = classB;
        }
    }
    View Code

     

    序列化結果如下,可以看到已經按照我們所預期的修改了命名空間前綴,這里要注意下需要自定義前綴的實體類添加的@XmlRootElement(namespace="http://www.lzrabbit.cn")注解時指定的namespace必須和package-info.java定義的前綴一致,否則還是會生成nsXX這樣的前綴

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <rabbit:classA xmlns:rabbit="http://www.lzrabbit.cn" xmlns:blog="http://www.cnblogs.com">
        <classAId>11</classAId>
        <ClassAName>A1</ClassAName>
        <classB>
            <ClassBId>22</ClassBId>
            <ClassBName>B2</ClassBName>
        </classB>
    </rabbit:classA>

    注意事項
    1.若jdk版本為1.6的需要需要添加jaxb-core-2.2.7.jar和jaxb-impl-2.2.7.jar兩個包的引用,否則即便設置了package-info的XmlSchema注解的xmlns注釋也不能生效,若為jdk 1.7的無需添加
    2.使用XmlSchema定義的前綴會對整個包生效,無法實現對每個實體類的單獨前綴定義,很不靈活,故此不推薦使用此方式

    解決方法二(推薦):
    同方法一若jdk版本為1.6需要添加jaxb-core-2.2.7.jar和jaxb-impl-2.2.7.jar兩個包的引用,不過方法二不需要添加package-info當然也就不需要定義XmlSchema
    思路就是實現NamespacePrefixMapper抽象類,並重寫getPreferredPrefix方法,看到方法名應該都明白了,對就是在序列化的時候重寫獲取命名空間前綴方法,為了簡潔這里使用類匿名內部類實現的

    marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapper() {
                    @Override
                    public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
                        if (namespaceUri.equals("http://www.lzrabbit.cn")) return "abc";
    return suggestion; } });

    如上所示,在序列化時判斷namespaceUri也就是我們定義的命名空間,然后返回我們自定義的前綴,其中的suggestion參數就是默認的前綴,有興趣的話打印下就會發現suggestion就是ns2之類的前綴,把要自定義前綴的命名空間都在這里判斷下就可以完全控制自定義前綴了,相對方法一來說可以實現對每個實體類的命名空間前綴控制,采用方法二后的序列化結果:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <abc:classA xmlns:abc="http://www.lzrabbit.cn">
        <classAId>11</classAId>
        <ClassAName>A1</ClassAName>
        <classB>
            <ClassBId>22</ClassBId>
            <ClassBName>B2</ClassBName>
        </classB>
    </abc:classA>

    采用方法二后的序列化方法

    package cn.lzrabbit;
    
    import java.io.StringReader;
    import java.io.StringWriter;
    
    import javax.xml.bind.*;
    
    import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
    import com.sun.xml.bind.v2.WellKnownNamespace;
    
    public class XmlUtil {
    
        public static String toXML(Object obj) {
            try {
                JAXBContext context = JAXBContext.newInstance(obj.getClass());
    
                Marshaller marshaller = context.createMarshaller();
                marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");// //編碼格式
                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);// 是否格式化生成的xml串
                marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);// 是否省略xm頭聲明信息
    
                marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapper() {
                    @Override
                    public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
                        if (namespaceUri.equals("http://www.lzrabbit.cn")) return "abc";
                        if (namespaceUri.contains("http://www.cnblogs.com")) return "blog";
                        return suggestion;
                    }
                });
    
                StringWriter writer = new StringWriter();
                marshaller.marshal(obj, writer);
                return writer.toString();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        @SuppressWarnings("unchecked")
        public static <T> T fromXML(String xml, Class<T> valueType) {
            try {
                JAXBContext context = JAXBContext.newInstance(valueType);
                Unmarshaller unmarshaller = context.createUnmarshaller();
                return (T) unmarshaller.unmarshal(new StringReader(xml));
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }
        }
    }
    View Code

     

現在我們基本解決了jaxb序列化xml的命名空間及前綴問題,但還是有很多問題,比如序列化和反序列化時如何忽略命名空間,如何使用@XmlRootElement控制每個實體類的默認命名空間也就是消除命名空間前綴

下一篇繼續深入,Java XML操作之JAXB玩轉命名空間 

最后給下jaxb-core-2.2.7.jar和jaxb-impl-2.2.7.jar兩個包的maven引用

<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-core</artifactId>
    <version>2.2.7</version>
</dependency>

<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.2.7</version>
</dependency>

也可以自行去官網下載 https://jaxb.java.net/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM