您的位置:首页 > 编程语言 > Java开发

java自学之路-----XML_解析技术

2014-11-09 10:59 477 查看
xml解析方式:

dom(Document Object Model):文档对象模型,是w3c组织解析xml的一种方式

sax(Simple API for XML):不是官方标准,但他是xml社区的标准,几乎所有的xml解析器都支持

xml的解析开发包:jaxp(sun),jdom(开源组织)和dom4j(开源组织)

dom和sax的区别{

1.dom解析的优点是对文档crud比较方便,缺点是占用内存比较大。原理:因为解析的时候需要将整个文档加载到内存,将文档的节点作为对象,在内存建立一个对象关系表

2.sax解析的优点是占用内存少,解析速度快,缺点是只适合作为文档的读取,不适合作为文档的crud。原理:读取一行解析一行的方式

}

JAXP{

1.是j2se的一部分,由javax.xml、org.w3c.dom、org.xml.sax包及其子包组成

2.在javax.xml.parsers包中,定义了几个工厂类,程序员可以通过调用工厂类得到xml文档的dom、sax的解析器,从而对xml文档进行解析

dom解析{读取完文档再解析

1.获得javax.xml.parsers包中的DocumentBuilderFactory(工厂模式,不可实例化,可以通过公共方法获得实例)

2.创建dom模式的解析器对象

3.解析xml文档,获得文档对象

4.通过文档对象可以通过标签名获得文档内的所有标签// 1.创建工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 2.通过工厂获得解析器对象
DocumentBuilder builder = factory.newDocumentBuilder();
// 3.通过对象解析文件,获得代表文档的document对象
Document document = builder.parse("src/book.xml");

// 获取标签,返回多个节点组成的list,标签名相同
NodeList list = document.getElementsByTagName("书名");
// 获取list中的节点,所有从0开始.获取第二个名为书名的节点
Node node = list.item(1);
// 得到该节点的内容
String content = node.getTextContent();
5.通过标签的节点又可以获得该标签的子标签:getChildNodes();

// 获得指定标签下的所有标签
public void list(Node node){
// 由于xml文档中的换行符也会作为节点的子节点。所以先判断该节点是否为标签
if(node instanceof Element){
System.out.println(node.getNodeName());
}
// 1.获取该标签下的所有子标签
NodeList list = node.getChildNodes();
// 2.遍历子标签,在获得它的子标签(递归)
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i);
list(child);
}
}

6.可以将节点转为标签对象,再使用属性名来获取属性值
Element book = (Element) document.getElementsByTagName("书").item(0);
book.getAttribute("name");

7.以下几个都是对内存中的文档对象进行修改,并未修改xml文档,就需要使用javax.xml.transformer包中的Transform方法把代表xml文件的document对象转换成某种格式后再输出到xml文件中,这个类的转换方法需要接受源(通过DOMSource关联要转换的document对象)和目的(用StreamResult对象表示数据的目的地)
8.使用文档对象创建标签:createElement("..."),为标签赋值之后,绑定在一个标签上

// 添加标签到文档中(添加指定的位置:insertBefore(newChild,refChild))
public void add() throws Exception{
// 1.获得文档对象
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/book.xml");
// 2.创建一个售价的标签
Element price = document.createElement("售价");
// 3.为该标签添加内容
price.setTextContent("49.00元");
// 4.将该标签放在第一个名为“书”的标签下
Element book = (Element) document.getElementsByTagName("书").item(0);
book.getAttribute("name");
book.appendChild(price);
// 5.由于以上代码知识将内存中的文档更新了,需要将内存中的文档更新到xml文档
//先获生产转换对象的工厂
TransformerFactory factory = TransformerFactory.newInstance();
//得到转化对象
Transformer ts = factory.newTransformer();
//将document对象封装成源,xml位置流封装成目的地
DOMSource source = new DOMSource(document);//直接使用创建对象的方法封装document
StreamResult result = new StreamResult(new FileOutputStream("src/book.xml"));//将xml文件的路径封装成目的流
//调用转化方法
ts.transform(source, result);
}

9.获得标签的element对象,使用setAttribute()设置属性
// 给标签添加一个属性
public void addAttr() throws Exception{
// 1.获得文档对象
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/book.xml");
// 2.获得要添加属性的标签,第一本书
Element book = (Element) document.getElementsByTagName("书").item(0);
// 3.为该节点添加属性
book.setAttribute("name", "java编程");
// 4.将内存中的文档更新到xml文件
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult("src/book.xml"));
}

10.获得标签的element对象,使用setTextContent()修改标签的内容
// 修改标签的内容
public void update() throws Exception{
// 1.获得文档对象
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/book.xml");
// 2.获得要修改内容的标签对象
Element book = (Element) document.getElementsByTagName("书").item(0);
// 3.修改内容
book.setTextContent("哈哈哈");
// 4.将内存中的文档更新到xml文件
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult(new FileOutputStream("src/book.xml")));
}

11.获得old的父标签Element对象,再使用removeChild(old)来删除old节点
// 删除某个标签
public void delete() throws Exception{
// 1.获得文档对象
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/book.xml");
// 2.获得要删除的书的标签对象
Element book = (Element) document.getElementsByTagName("书").item(0);
// 3.获得书的父标签删除。
book.getParentNode().removeChild(book);
// 4.将内存中的文档更新到xml文件
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult(new FileOutputStream("src/book.xml")));
}
注意:dom解析下,xml文档的每一个组成部分都用一个对象表示,例如标签的Element和属性的Attr,但不管什么对象都是Node的子类,所以标签可以当做节点来对待

}

sax解析{边读取边解析

采用事件处理方式解析xml文件,该技术涉及两个部分:

解析器:使用JAXP的API创建,创建出解析器后就可以通过读取器去解析某个
xml文档。在解析的时候,只要解析到文件的一个组成部分就会去调用事件处理器的一个方法,在调用方法的时候会将当前解析的xml文件内容作为方法的参数传给事件处理器。

public void parse() throws Exception{
// 1.获得解析器工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
// 2.获得解析器对象
SAXParser parser = factory.newSAXParser();
// 3.获得解析器的读取器
XMLReader reader = parser.getXMLReader();
// 4.定义读取器的内容处理器
reader.setContentHandler(new MyHandler());
// 5.使用读取器进行解析xml文件
reader.parse("src/book.xml");
事件处理器:由程序员编写,通过事件处理器方法的参数就可轻松得到sax解析器解析到的数据,从而对数据进行处理(通过事件处理器可以知道sax确实只适合进行读取操作,不适合CRD)
// 定义处理器类,实现内容处理器接口。如果不想实现过多方法可以继承一个默认实现类DefaultHandler.只覆盖想要覆盖的方法
// class MyHandler extends DefaultHandler
class MyHandler implements ContentHandler{

// 解析到开始标签的处理方法
@Override
public void startElement(String uri, String localName, String name,
Attributes atts) throws SAXException {//将该标签的所有属性通过Attributes对象传入
// 直接把开始标签输出
System.out.println("<"+ name + ">");
}

// 解析到内容的处理方法
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// 直接输出内容
System.out.println(new String(ch, start, length));
}

// 解析到结束标签的处理方法
@Override
public void endElement(String uri, String localName, String name)
throws SAXException {
System.out.println("</"+ name + ">");
} }
......实现所有方法}
定义一个想要获得某个标签内容的处理器:
// 继承实现类,覆盖部分方法
class GetContentHandler extends DefaultHandler{
// 定义一个变量,获得当前处理的是哪个标签
String currentname = null;
String needname= "作者";
// 定义想要获得第几个标签的内容
int neednumber = 2;
int number = 0;//当前是第几个该标签

// 需要使用处理开始标签,结束标签,内容的方法
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
currentname = qName;
number++;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// 如果当前是想要的标签则输出该内容
if(currentname.equals(needname) && neednumber==number){
System.out.println(new String(ch, start, length));
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// 将当前处理的标签名置为空,方便下次读取。如果不清空就会把结束标签后的换行符也当为内容来处理,就会影响数据
currentname = null;
}
}例:结合反射将sax解析的数据封装到指定的对象中
class BeanHandler extends DefaultHandler{
private List list = new ArrayList();
private String currentname = null;
private Class clazz;
private Object bean = null;
public BeanHandler(Class clazz) {
super();
this.clazz = clazz;
}

@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
currentname = qName;
if("书".equals(currentname)){
try {
bean = clazz.newInstance();
} catch (Exception e) {
}
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
try {
Field f = clazz.getDeclaredField(currentname);
f.setAccessible(true);
f.set(bean, new String(ch,start,length));

} catch (Exception e) {

}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("书".equals(qName)){
list.add(bean);
bean = null;
}
currentname = null;
}

public List getList() {
return list;
}

}

}

}

DOM4j{

是一个简单、灵活的开源的库,性能优异,功能强大和极易使用。具体使用方法查看dom4j的快速入门文档

// 1.创建一个SAX读取器
SAXReader reader = new SAXReader();
// 2.通过读取器直接读取文件。
Document document = reader.read(new File("src/book.xml"));
// 3.获取根节点
Element root = document.getRootElement();
// 4.获取根节点的子标签(有嵌套就需要一层一层的获得标签)
//获得根节点下的第一个书标签
Element book = (Element) root.elements("书").get(1);
// 5.获得这个书的书名这个标签的内容及属性name的值
String content = book.element("书名").getText();
String value = book.element("书名").attributeValue("name");
//		为第一个书的标签添加一个子标签
public void add() throws DocumentException, IOException{
Document document = new SAXReader().read(new File("src/book.xml"));
//		获得文档对象后,获得根节点再获得需要添加的标签
Element book = document.getRootElement().element("书");
//		为该标签添加子标签并赋值
book.addElement("售价").setText("50.00元");

//		再将内存中的文档对象写到xml文件中
//使用一个文件流来创建将文档写到文件的对象xmlwriter
//乱码问题:1.设置一个格式输出器,设置它的编码,要与xml文档相同的编码
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
//  2.如果使用字符流需要指定编码表,如果使用字节流则不需要(字节流会自己查格式器的码表)
//		XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
XMLWriter writer = new XMLWriter(new OutputStreamWriter(new FileOutputStream("src/book.xml"),"UTF-8"),format);
writer.write(document);
writer.close();
}

//	在指定位置添加一个标签
Document document = new SAXReader().read(new File("src/book.xml"));
Element book = document.getRootElement().element("书");
List list = book.elements();
//		使用documentHelper来创建标签,document无该方法
Element price = DocumentHelper.createElement("售价");
price.setText("100.00元");
//		将price存到list中的索引为2的地方(第三个节点),自动将索引为2或以后的后移
list.add(2, price);<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>//更新到xml文件
<span style="white-space:pre">		</span>OutputFormat format = OutputFormat.createPrettyPrint();
<span style="white-space:pre">		</span>format.setEncoding("UTF-8");
<span style="white-space:pre">		</span>XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
<span style="white-space:pre">		</span>writer.write(document);
<span style="white-space:pre">		</span>writer.close();

如果要获得指定的标签,结合xpath使用即可:
SAXReader reader = new SAXReader();
Document document = reader.read(new File("src/book.xml"));
List list = document.selectNodes("//作者");//查找多个
Node node = document.selectSingleNode("//作者");//查找单个例:
//xpath应用在查找数据
public void login(String username, String password) throws DocumentException{
Document document = new SAXReader().read(new File("src/users.xml"));
//		获得一个属性名为name值为username并且另一个属性为password,值为password的user标签
Node node = document.selectSingleNode("//user[@name='"+username+"'and @password='"+password+"']");
if(node == null){
System.out.println("失败");
}else{
System.out.println("成功");
}
}


}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java xml