一、 XML的三种解析方法 二、适配器模式简介 三、XML 文档使用栈分析

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

<book>
    <b>
        <作者>张三</作者>
        <价格>19000</价格>
    </b>
    <b>
        <作者>李四</作者>
        <价格>12.00</价格>
    </b>

</book>


一、XML的三种解析方式

1.  dom解析

java JDK中 提供的 解析方法, 特别的是,它可以修改 XML文件中的内容

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;       
        @Test
	public void XMLParse() throws Exception {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document d = db.parse("book.xml");
		String s = d.getElementsByTagName("作者").item(0).getTextContent();
		System.out.println(s);
		s = d.getElementsByTagName("价格").item(0).getTextContent();
		System.out.println(s);
	}

	@Test
	public void XMLTransfer() throws Exception {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();

		Document d = db.parse("book.xml");

		d.getElementsByTagName("价格").item(0).setTextContent("19000");

		TransformerFactory t = TransformerFactory.newInstance();
		Transformer newTransformer = t.newTransformer();
		Source xmlSource = new DOMSource(d);
		Result outputTarget = new StreamResult("book.xml");
		newTransformer.transform(xmlSource, outputTarget);
	}

2. sax解析   

这里我最想说的是 里面使用到了 适配器设计模式 

DefaultHandler   此类实现了 ContentHandler 等多个接口  去都是一个空的方法 实现了接口中的方法声明
这样 就是的程序员可以 定义自的handler 去继承 DefaultHandler ,只实现自己感兴趣的方法就可以了

        @Test
	public void SAXParse() throws Exception {

		SAXParserFactory spf = SAXParserFactory.newInstance();
		SAXParser sp = spf.newSAXParser();
		XMLReader xr = sp.getXMLReader();

		xr.setContentHandler(new SaxHandler());

		xr.parse("book.xml");

	}

	class SaxHandler extends DefaultHandler {    //适配器设计模式

		ArrayList<Book> list = null;
		Book book = null;
		String str = null;

		@Override
		public void characters(char[] ch, int start, int length)
				throws SAXException {

			 if ("作者".equals(str)) {
				book.setAuthor(new String(ch, start, length));

			} else if ("价格".equals(str)) {
				book.setPrivce(new String(ch, start, length));
			}

		}

		@Override
		public void startDocument() throws SAXException {

			list = new ArrayList<>();
		}

		@Override
		public void endDocument() throws SAXException {

			System.out.println(list);
		}

		@Override
		public void startElement(String uri, String localName, String qName,
				Attributes attributes) throws SAXException {

			if ("作者".equals(qName)) {
				str = new String("作者");

			} else if ("价格".equals(qName)) {
				str = new String("价格");
			} else if ("b".equals(qName)) {
				book = new Book();
			}

		}

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

			if ("作者".equals(qName)) {
				str = null;

			} else if ("价格".equals(qName)) {
				str = null;
			} else if ("b".equals(qName)) {
				list.add(book);
				book = null;
			}

		}

	}

3. xmlpull解析   需要自己导入xmlpull 的 jar包

Android 中经常使用它来 解析 XML

    @Test
    public void PullXMLParser() throws Exception {
        XmlPullParserFactory xppf = XmlPullParserFactory.newInstance();

        XmlPullParser xpp = xppf.newPullParser();
        xpp.setInput(new FileInputStream("book.xml"), "utf-8");

        ArrayList<Book> list = null;
        Book book = null;
        int type = 0;
        while ((type = xpp.getEventType()) != XmlPullParser.END_DOCUMENT) {
            switch (type) {
            case XmlPullParser.START_DOCUMENT:
                list = new ArrayList<>();
                break;
            case XmlPullParser.START_TAG:
                book = new Book();
                if ("作者".equals(xpp.getName())) {
                    book.setAuthor(xpp.nextText());

                } else if ("价格".equals(xpp.getName())) {
                    book.setPrivce(xpp.nextText());

                }
                break;
            case XmlPullParser.END_TAG:
                if ("b".equals(xpp.getName())) {
                    list.add(book);
                    book = null;
                }
                break;
            }
            xpp.next();
        }
        System.out.println(list);
    }



三、 自己使用 数据结构 栈 来实现对 XML 文件的简单解析工作

以上述XML代码为例,使用栈结构来完成对XML的解析

<book>
<b>

    <作者>
        张三</作者>

    <价格>
        19000
    </价格>
</b>

<b>

    <作者>
        李四</作者>

    <价格>
        12.00
    </价格>
</b>
</book>

为了突出终点我将每一个标签保存为一行   使用正确格式的XML 文档

	@Test
	public void MyXMLParse() throws Exception {
		
		Stack<String> stack = new Stack<>();	
		BufferedReader br = new BufferedReader(new FileReader("book.xml"));

		String str = null;
		while ((str = br.readLine()) != null) {
			if(isEndTag(str) == false) {	//不是一个结束标签
				stack.add(str);
			} else {						//是一个结束标签
				while(true) {
					if(ToBeginTag(str).equals(stack.peek()) == true) {
						stack.pop();
						break;
					}else {
						System.out.println(stack.pop());
					}
				}
			}
		}
		System.out.println(stack.size() == 0);
		br.close();
	}
	
	public boolean isText(String str) {
		if(str.substring(0,1).equals("<")) {
			return false;
		}
		return true;
	}
	
	public boolean isEndTag(String str) {
		if ("/".equals(str.substring(1, 2))) {
			return true;
		}
		return false;
	}

	public String ToBeginTag(String str) {
		if (isEndTag(str))
			return str.substring(0, 1) + str.substring(2);
		else
			return str;
	}

解释原理  

使用建模的思想  可以把 XML转换为 

(((张三)(19000))((李四)(12.00)))
从左到右遍历字符串

如果遇到 ‘(’左括号和汉字 那么 就进栈

如果 遇到 ‘)’右括号  那么 就弹栈  知道 弹出一个 ‘(’ 就停止。

这样遍历完之后, 如果栈为空那么就说明 括号是匹配的


情景分析

在遍历前三个括号的时候 它们都是左括号     栈情况为   ------>   '('          '('         '('

遇到 ‘张三’  不是右括号 就进栈      栈情况为  ----->  '('          '('         '('   '张三'

继续遍历遇到 ‘)’    那么弹出 ‘张三’并打印  然后弹出 ‘(’ 停止弹栈     栈情况为  ------> '('          '(' 

遇到 ‘(’  和 ‘19000’  都会进栈    栈情况为 ------>  '('          '('      '('    '19000'

遇到 ‘)’ 那么弹出 ‘19000’并打印   然后弹出 ‘(’  停止弹栈     栈情况为  ------> '('          '('

遇到 ‘)’ 那么弹出 ‘(’        栈情况为  ------> '('       

......   最后结果 栈为空 表示 表达式中的括号是正确匹配的


 







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值