JAXB玩转命名空间

声明:如果你正在发愁xml命名空间及其前缀问题,那么请继续,否则请跳过

本文讲解使用jaxb结合dom4j的XMLFilterImpl过滤器实现序列化和反序列化的完全控制

主要实现以下功能

  • 序列化及反序列化时忽略命名空间
  • 序列化时使用@XmlRootElement(namespace="http://www.lzrabbit.cn")注解作为类的默认命名空间,彻底消除命名空间前缀
  • 序列化时引用类有不同命名空间时也不会生成命名空间前缀,而是在具体的xml节点上添加相应的xmlns声明
  • 其它的xml节点命名及命名空间需求
  • 同一个包下有多个命名空间
  • 自定义命名空间前缀

依赖的jar dom4j

 <dependency>

            <groupId>dom4j</groupId>

            <artifactId>dom4j</artifactId>

            <version>1.6.1</version>

 </dependency>

主要原理就是在序列化和反序列化时通过XMLFilterImpl的匿名实现类实现命名空间及xml节点名称的控制,实现多样化需求,废话不多说直接上代码,有更多个性化需求的看官请自行扩展

JAXB玩转命名空间
package cn.lzrabbit.util;



import java.io.StringReader;

import java.io.StringWriter;



import javax.xml.bind.*;

import javax.xml.transform.sax.SAXSource;



import org.dom4j.io.OutputFormat;

import org.dom4j.io.XMLWriter;

import org.xml.sax.Attributes;

import org.xml.sax.InputSource;

import org.xml.sax.SAXException;

import org.xml.sax.XMLReader;

import org.xml.sax.helpers.XMLFilterImpl;

import org.xml.sax.helpers.XMLReaderFactory;



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头声明信息



            StringWriter out = new StringWriter();

            OutputFormat format = new OutputFormat();

            format.setIndent(true);

            format.setNewlines(true);

            format.setNewLineAfterDeclaration(false);

            XMLWriter writer = new XMLWriter(out, format);



            XMLFilterImpl nsfFilter = new XMLFilterImpl() {

                private boolean ignoreNamespace = false;

                private String rootNamespace = null;

                private boolean isRootElement = true;



                @Override

                public void startDocument() throws SAXException {

                    super.startDocument();

                }



                @Override

                public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {

                    if (this.ignoreNamespace) uri = "";

                    if (this.isRootElement) this.isRootElement = false;

                    else if (!uri.equals("") && !localName.contains("xmlns")) localName = localName + " xmlns=\"" + uri + "\"";



                    super.startElement(uri, localName, localName, atts);

                }



                @Override

                public void endElement(String uri, String localName, String qName) throws SAXException {

                    if (this.ignoreNamespace) uri = "";

                    super.endElement(uri, localName, localName);

                }



                @Override

                public void startPrefixMapping(String prefix, String url) throws SAXException {

                    if (this.rootNamespace != null) url = this.rootNamespace;

                    if (!this.ignoreNamespace) super.startPrefixMapping("", url);



                }

            };

            nsfFilter.setContentHandler(writer);

            marshaller.marshal(obj, nsfFilter);

            return out.toString();



        } catch (Exception e) {

            throw new RuntimeException(e);

        }

    }



    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));

            SerializeUtil obj = new SerializeUtil();

            XMLReader reader = XMLReaderFactory.createXMLReader();

            XMLFilterImpl nsfFilter = new XMLFilterImpl() {

                private boolean ignoreNamespace = false;



                @Override

                public void startDocument() throws SAXException {

                    super.startDocument();

                }



                @Override

                public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {

                    if (this.ignoreNamespace) uri = "";

                    super.startElement(uri, localName, qName, atts);

                }



                @Override

                public void endElement(String uri, String localName, String qName) throws SAXException {

                    if (this.ignoreNamespace) uri = "";

                    super.endElement(uri, localName, localName);

                }



                @Override

                public void startPrefixMapping(String prefix, String url) throws SAXException {

                    if (!this.ignoreNamespace) super.startPrefixMapping("", url);

                }

            };

            nsfFilter.setParent(reader);

            InputSource input = new InputSource(new StringReader(xml));

            SAXSource source = new SAXSource(nsfFilter, input);

            return (T) unmarshaller.unmarshal(source);

        } catch (Exception e) {

            throw new RuntimeException(e.getMessage());

        }

    }

}
View Code

示例实体类

JAXB玩转命名空间
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;



    @XmlElement(namespace="http://www.cnblogs.com/")

    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;

    }

}



import javax.xml.bind.annotation.*;



@XmlAccessorType(XmlAccessType.FIELD)

public class ClassB {

    private int ClassBId;

    private String ClassBName;



    public int getClassBId() {

        return ClassBId;

    }



    public void setClassBId(int classBId) {

        this.ClassBId = classBId;

    }



    public String getClassBName() {

        return ClassBName;

    }



    public void setClassBName(String classBName) {

        this.ClassBName = classBName;

    }

}
View Code

调用

import cn.lzrabbit.util.XmlUtil;



public class MainRun {



    /**

     * @param args

     */

    public static void main(String[] args) {



        ClassB classB = new ClassB();

        classB.setClassBId(22);

        classB.setClassBName("B2");



        ClassA classA = new ClassA();

        classA.setClassAId(11);

        classA.setClassAName("A1");

        classA.setClassB(classB);



        System.out.println(XmlUtil.toXML(classA));

    }



}

输出结果:

<?xml version="1.0" encoding="UTF-8"?>

<classA xmlns="http://www.lzrabbit.cn/">

  <classAId>11</classAId>

  <ClassAName>A1</ClassAName>

  <classB xmlns="http://www.cnblogs.com/">

    <ClassBId>22</ClassBId>

    <ClassBName>B2</ClassBName>

  </classB>

</classA>

可以看到输出的xml完全达到我们的预期

实现细节都在代码里面了,很简单,当遇到有特殊需求的xml命名空间问题时,再也不用愁了

 

你可能感兴趣的:(JAXB)