简单程序时xml相较数据库要更为简单直接,一个文本文件就足够记录一些简单的条目了。同时作为配置文件选择xml也是极好的。java操作xml的技术应该有不少,在这里只谈DOM、SAX,两者应用都很广泛,在不同情况下都有各自优点。
对比DOM和SAX,可以简单理解为:
DOM是直接把xml全部读取放到内存中然后操作,并包含一整套方法完成对xml文档的操作;
SAX要更为简单,只能读取xml文件,一边读源文件一边触发事件,程序员需要在事件中加入想要的功能,因而程序员能更大程度控制处理xml文档的资源开销。
这么看来如果只是要去xml文档中查数据的话SAX是比较适合的,如果要增删查改xml的内容,似乎应该用DOM,功能丰富,只不过要占用多一些内存。
先看看SAX,直接给完整代码
import java.io.File;
import javax.xml.parsers.*;
import org.xml.sax.helpers.*;
import org.xml.sax.*;
public class saxTest extends DefaultHandler{
private String ElementName;
public saxTest(){
this.ElementName="";
}
public void startDocument(){
}
public void startElement(String uri,String localName,String qName,Attributes attributes){
this.ElementName=qName;
if(qName.equals("ElementName1")){
System.out.println(attributes.getValue("id"));//获取标签的属性,既可以用属性名,也可以用下标
System.out.println(attributes.getValue(0));
}
}
public void characters(char[] ch,int start,int length){
String str=new String(ch,start,length);
System.out.println(str);
}
public void endElement(String uri,String localName,String qName){
}
public void endDocument(){
}
public static void main(String[] args)throws Exception{
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser parser=factory.newSAXParser();
parser.parse(new File("xmlsrc.xml"),new saxTest());
}
}
相应的xml文档
<?xml version="1.0" encoding="gb2312"?>
<ElementName1 id="1">
abcdefg
</ElementName1>
运行结果应该是
1
1
abcdefg
比较让人疑惑的是除了main以外还有那么多方法都在哪里调用的?
main方法中有一句
parser.parse(new File("xmlsrc.xml"),new saxTest());
传入的参数是xml文档路径,一个继承DefaultHandler的saxTest实例
parser.parse()这个方法就会触发SAX解析器开始解析xml文档,当遇到文档中的标签时就会触发事件。比如
读取到
<?xml version="1.0" encoding="gb2312"?>
触发startDocument()事件
<ElementName1 id="1">
触发startElement()事件
abcdefg
触发characters()事件
</ElementName1>
触发endElement()事件
。。。。。。
程序员的工作就是在这些事件中加入自己的代码
至于DOM,它的背景这里就不赘述了,给一个百度百科的链接
DOM操作xml文件会用Document、Node、NodeList、Element这几个类的实例来表示xml文件中的各个节点
Document:表示整个xml文档
Node、Element:表示文档中的节点,这两个类的实例是可以相互强制转换的
NodeList:elementInstance.getChildNodes()返回NodeList实例,NodeListInstance.item(i)就可以获得第i个子节点
直接来代码,粘贴到eclipse中会自动提示需要引用的包
public static void main(String[] args){
try {
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
dbf.setIgnoringElementContentWhitespace(true);
Document doc = dbf.newDocumentBuilder().parse(“xmlsrc.xml");
// 以上获取一个Document实例,没什么可变的
Element root = doc.getDocumentElement();//根节点
NodeList nodes_level1 = root.getChildNodes();//获得根节点下所有子节点
FindAll(nodes_level1);
} catch (ParserConfigurationException e) {
System.out.println(e.getMessage());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void FindAll(NodeList nodes_level1){
//获得一个NodeList后,获取其子节点有关数据,但子节点可能还包含二级节点,在以下for循环最后使用了迭代,这样就能遍历所有节点了
for(int i=0; i<nodes_level1.getLength(); i++){
Node node_level2 = nodes_level1.item(i);
if(node_level2.getNodeType() == Node.ELEMENT_NODE){
try{
System.out.println(node_level2.getAttributes().getNamedItem("name").getNodeValue());//获得指定属性值
}catch(Exception e){}
System.out.println(
node_level2.getTextContent().trim());//获得标签之间的值
System.out.println(
node_level2.getNodeName());//获得标签名
System.out.println(
node_level2.getAttributes().item(0));//获得标签包含的属性
if(!(node_level2.getChildNodes() == null)){
FindAll(node_level2.getChildNodes());
}
}
}
还有一些 DOM 常用的方法:
Node.getFirstChild() 、Node.getLastChild():返回给定 Node 的第一个和最后一个子节点。
Node.getNextSibling() 、 Node.getPreviousSibling():返回给定 Node 的下一个和上一个同级节点。
Element.getAttribute(String attrName):对于给定的 Element,返回名为 attrName 的属性的值。