原文链接http://zhhll.icu/2020/08/16/xml/DOM/DOM%E8%A7%A3%E6%9E%90/
DOM是基于属性结构的XML解析方式,会将整个XML文档读入内存并构建一个DOM树,基于这棵树型结构对各个节点进行操作。XML文档中每个成分都是一个节点,整个文档是一个文档节点,每个XML标签对应一个元素节点,包含在XML标签中的文本是文本节点,每一个XML属性是一个属性节点,注释属于注释节点。
DOM树所提供的随机访问方式很灵活方便,可以任意地控制整个XML文档中的内容,但是DOM分析器把整个XML文件转化为DOM树放到了内存中,当文档比较大或者结构比较复杂时,对内存需求比较高。
下面以mybatis的一个mapper.xml为例讲解各个方法
<mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="funkyNumber" property="funkyNumber"/>
<result column="roundingMode" property="roundingMode"/>
resultMap>
<select id="getUser" resultMap="usermap">
select * from users
select>
<insert id="insert">
insert into users (id, name, funkyNumber, roundingMode) values (
#{id}, #{name}, #{funkyNumber}, #{roundingMode}
)
insert>
<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="funkyNumber" property="funkyNumber"/>
<result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
resultMap>
<select id="getUser2" resultMap="usermap2">
select * from users2
select>
<insert id="insert2">
insert into users2 (id, name, funkyNumber, roundingMode) values (
#{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
)
insert>
mapper>
介绍一下DOM解析中的核心接口
public static Document getDefaultDocument(File file) throws ParserConfigurationException, IOException, SAXException {
// 创建DocumentBuilderFactory,用于取得DocumentBuilder
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
// 使用DocumentBuilder进行DOM树的转换操作,读取指定的xml文件
return builder.parse(file);
}
// 获取mapper节点
NodeList mapperList = document.getElementsByTagName("mapper");
for(int i = 0;i<mapperList.getLength();i++){
Node mapperNode = mapperList.item(i);
if(mapperNode.hasAttributes()){
// 找到mapper节点的namespace属性节点
Node namespace = mapperNode.getAttributes().getNamedItem("namespace");
// namespace属性节点内容
System.out.println(namespace.getNodeValue());
}
if(mapperNode.hasChildNodes()){
// mapper节点的子节点
NodeList childNodes = mapperNode.getChildNodes();
// 遍历子节点
for(int j = 0;j<childNodes.getLength();j++){
Node childNode = childNodes.item(j);
if("resultMap".equals(childNode.getNodeName())){
//TODO
} else if("select".equals(childNode.getNodeName())){
//TODO
} else if("insert".equals(childNode.getNodeName())){
//TODO
}
}
}
}
// 创建test节点作为根节点
Element root = document.createElement("test");
// 创建type属性
Attr type = document.createAttribute("type");
type.setNodeValue("test");
// 创建id节点
Element id = document.createElement("id");
// 创建文本节点,并放到id节点中
id.appendChild(document.createTextNode("001"));
// 创建name节点
Element name = document.createElement("name");
// 创建文本节点,并放到name节点中
name.appendChild(document.createTextNode("张三"));
// 设置属性节点
root.setAttributeNode(type);
// 将节点放入父节点中
root.appendChild(id);
root.appendChild(name);
document.appendChild(root);
将生成的xml保存到文件中,需要使用TransformerFactory、Transformer、DOMSource和StreamResult四个类来完成
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer;
try {
transformer = factory.newTransformer();
} catch (TransformerConfigurationException e) {
throw new RuntimeException("创建Transformer失败",e);
}
// 设置xml属性 只设置了version和ecoding 还需要设置其他属性可以从OutputKeys中查找
transformer.setOutputProperty(OutputKeys.VERSION,"1.0");
transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
// dom数据源
DOMSource source = new DOMSource(document);
// 目的地
StreamResult result = new StreamResult(new File(fileName));
try {
// 进行转换
transformer.transform(source,result);
} catch (TransformerException e) {
throw new RuntimeException("输出文件错误",e);
}
下面介绍一些DocumentBuilderFactory中用来设置解析器行为的一些配置可能会用到的方法,但是就不写代码示例了
// 该方法指定解析器是否将CDATA节点转换为文本节点,以及是否将它和周围的文本节点合并,默认false
public void setCoalescing(boolean coalescing)
// 指定解析器是否展开外部实体引用,如果为true,外部数据将插入文档,默认true
public void setExpandEntityReferences(boolean expandEntityRef)
// 指定解析器是否忽略文档中的注释。默认false
public void setIgnoringComments(boolean ignoreComments)
// 指定是否忽略元素内容中的空白。默认false
public void setIgnoringElementContentWhitespace(boolean whitespace)
// 指定是否支持XML的名称空间。默认false
public void setNamespaceAware(boolean awareness)
// 是否验证文档,默认false
public void setValidating(boolean validating)
由于本身的博客百度没有收录,博客地址http://zhhll.icu