Java XML 解析
Java XML Dom解析工具
缩进等
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
从其他的Document中引入Element
有时会有需求,要从其他的Xml中读取某些节点,添加到当前Xml中,只需要使用 Document.importNode
Document source = XmlUtil.load("1.xml"), target = XmlUtil.getDocumentBuilder().newDocument();
Element node = source.getDocumentElement();
Node imported = target.importNode(node, true);
引入Element时 处理namespace
如果引入节点的命名空间和当前不同,需要处理命名空间问题
XmlUtil.renameNamespaceRecursive(imported, "http://fuckingday.com");
工具类
package org.go;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.Writer;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class XmlUtil {
public static DocumentBuilder getDocumentBuilder() {
DocumentBuilder parser = null;
try {
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
df.setNamespaceAware(true);
parser = df.newDocumentBuilder();
return parser;
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
return null;
}
public static Document load(String filePath) throws SAXException, IOException {
DocumentBuilder parser = getDocumentBuilder();
InputStream in = new FileInputStream(filePath);
Document document = parser.parse(in);
return document;
}
public static void toFile(Document doc, String file) throws TransformerException {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.transform(new DOMSource(doc), new StreamResult(file));
}
public static String toString(Document doc) throws TransformerException {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
Writer writer = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(writer));
return writer.toString();
}
public static void renameNamespaceRecursive(Node node, String namespace)
{
Document document = node.getOwnerDocument();
if (node.getNodeType() == Node.ELEMENT_NODE)
{
document.renameNode(node, namespace, node.getNodeName());
}
NodeList list = node.getChildNodes();
for (int i = 0; i < list.getLength(); ++i)
{
renameNamespaceRecursive(list.item(i), namespace);
}
}
}
从 注解和继承 到 JAXB中的注意事项
注解在继承中的行为
如果一个父类添加了一个注解,子类是否能取到这个注解呢?如下
package inheritance;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class Main {
public static void main(String[] args) {
Type t = Son.class.getAnnotation(Type.class);
if (t != null) {
System.out.println(t.name());
}
}
}
@Type(name = "Father")
class Father {
}
class Son extends Father {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Type {
String name();
}
如上代码,注解不会被子类继承。如果想注解也被子类继承,该怎么办呢?
只需要在注解定义里修改一下,添加@Inherited
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Type {
String name();
}
关于@Inherited需要注意的:
- 只能作用于继承,不能作用于接口实现
JAXB 的注解
@XmlAccessorType用于标注该类的成员是否用于绑定到XML,例如XmlAccessType.PUBLIC_MEMBER表示,所有public字段都会被绑定(除去@XmlElement和@XmlTransient的标记,他们优先级更高)。
这个注解就是标记了@Inherited。
我们知道序列化顺序可以由@XmlType(propOrder)去设置,那么继承后是什么样子呢?
package inheritance;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
public class Main {
public static void main(String[] args) throws Exception {
JAXBContext ctx = JAXBContext.newInstance(Son.class);
Marshaller ms = ctx.createMarshaller();
ms.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
ms.marshal(new Son(), System.out);
}
}
@XmlRootElement(name = "Father")
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlType(propOrder = { "two", "one" })
class Father {
@XmlElement
private String one = "one";
@XmlElement
public String two = "two";
}
@XmlRootElement(name = "Son")
@XmlAccessorType(XmlAccessType.NONE)
@XmlType(propOrder = { "four", "three" })
class Son extends Father {
@XmlElement
public String three = "three";
@XmlElement
public String four = "four";
}
上述代码会输出
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Son>
<two>two</two>
<one>one</one>
<four>four</four>
<three>three</three>
</Son>
即父类成员先序列化,再子类成员,顺序由各自类的@XmlType设置的顺序决定。
那么如果子类一定想控制父类成员的序列化顺序,而且不同的子类还想各自定义父类成员的序列化顺序怎么办?(CNM, 屁事真多)
好吧,JAXB还是可以满足这种屁事儿的。
package inheritance;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
public class Main {
public static void main(String[] args) throws Exception {
go(Son.class);
go(Daughter.class);
}
private static void go(Class<?> clz) throws Exception {
JAXBContext ctx = JAXBContext.newInstance(clz);
Marshaller ms = ctx.createMarshaller();
ms.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
ms.marshal(clz.newInstance(), System.out);
}
}
@XmlTransient
class Father {
@SuppressWarnings("unused")
private String one = "one";
public String two = "two";
}
@XmlRootElement(name = "Son")
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlType(propOrder = { "four", "three", "two" })
class Son extends Father {
@XmlElement
public String three = "three";
@XmlElement
public String four = "four";
}
@XmlRootElement(name = "Daughter")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = { "one", "two", "three", "four" })
class Daughter extends Father {
@XmlElement
public String three = "three";
@XmlElement
public String four = "four";
}
上述代码将输出
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Son>
<four>four</four>
<three>three</three>
<two>two</two>
</Son>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Daughter>
<one>one</one>
<two>two</two>
<three>three</three>
<four>four</four>
</Daughter>
解释如下:
- 要想每个子类去控制父类成员,必须把父类标记成@XmlTransient,而且子类@XmlType的propOrder要负责所有自己要序列化的成员。
- 类Son的@XmlAccessorType标注为XmlAccessType.PUBLIC_MEMBER,意味着Son只序列化Public字段。加上父类的public成员,Son共有3个public成员,所以@XmlType(propOrder)写了三个成员的顺序。
- 类Daughter的@XmlAccessorType标注为XmlAccessType.FIELD,意味着所有父类和自己的成员都会序列化,于是标记四个成员的顺序。
忽略dtd
import java.io.FileReader;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXSource;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
public class Demo2 {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(MyBean.class);
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
spf.setFeature("http://xml.org/sax/features/validation", false);
spf.setNamespaceAware(true);
XMLReader xmlReader = spf.newSAXParser().getXMLReader();
InputSource inputSource = new InputSource(
new FileReader("myfile.xml"));
SAXSource source = new SAXSource(xmlReader, inputSource);
Unmarshaller unmarshaller = jc.createUnmarshaller();
MyBean foo = (MyBean) unmarshaller.unmarshal(source);
}
}

浙公网安备 33010602011771号