我们先了解xml有什么用,它是一个通用的数据交互的格式,对,就是做数据交互的,我们知道JSON也是做数据交互的。怎么来理解这个数据交互呢,例如我们现在有一个java项目,后台是java写的,前端是js,现在有个请求,需要查询这个order的信息,我先从数据库查出来这条数据,搭orm映射,存放到一个javaBean中,之后我们需要将这个javaBean的数据传递到前端js来接受,后台java的语法,js是不认识这个东西,所以我们需要定一个达成共识的标准,按照这种标准的语法来写,java认识,js也认识,这样问题就解决了,这种标准的作用的就做数据交互。
json和xml 比较 json相对比较轻,写法也简单,像后台和页面的交互,这种数据量不大,用json来实现,但是如果是不同系统进行对接,这个时候就需要使用xml,我们平时都是使用webService来进行不同系统的交互,xml就是webService的重要组成部分。
xml解析的分为两种方式:
1)dom:基于xml文件树结构进行解析,每个元素都是node。
2)SAX:基于事件进行解析。
1.DOM解析
<?xml version="1.0" encoding="UTF-8"?>
<employess>
<employes>
<name>zhangsan</name>
<!-- 0为男性 1位女性 -->
<sex>0</sex>
<age>22</age>
</employes>
<employes>
<name>xiangli</name>
<!-- 0为男性 1位女性 -->
<sex>1</sex>
<age>20</age>
</employes>
</employess>
public class TestDom {
public static void main(String[] args) throws ParserConfigurationException, Exception{
ClassLoader classLoader = TestDom.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("test.xml");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder= factory.newDocumentBuilder();
Document document = builder.parse(resourceAsStream);
NodeList employess = document.getElementsByTagName("employes");
for (int i = 0; i < employess.getLength(); i++) {
System.out.println("第["+i+"]个员工");
System.out.println("员工姓名:"+document.getElementsByTagName("name").item(i).getFirstChild().getNodeValue());
System.out.println("员工性别:"+document.getElementsByTagName("sex").item(i).getFirstChild().getNodeValue());
System.out.println("员工年龄:"+document.getElementsByTagName("age").item(i).getFirstChild().getNodeValue());
}
}
}
第[0]个员工
员工姓名:zhangsan
员工性别:0
员工年龄:22
第[1]个员工
员工姓名:xiangli
员工性别:1
员工年龄:20
我们只需要拿到Document对象,就可以根据API对它的每个节点进行增删改查,写法比较简单
2.SAX解析
SAX解析是基于事件,我们需要继承DefaultHandler ,然后重写它的一些方法,这些方法会在解析xml触发一些特定事件的时候调用,我们可以在方法里面做一些数据保存的操作。
public class DefaultHandler
implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler
{
/**
* Receive notification of the beginning of the document.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the beginning
* of a document (such as allocating the root node of a tree or
* creating an output file).</p>
*
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#startDocument
*/
public void startDocument ()
throws SAXException
{
// 开始解析xml 调用此方法 (non-Javadoc)
}
/**
* Receive notification of the end of the document.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the end
* of a document (such as finalising a tree or closing an output
* file).</p>
*
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#endDocument
*/
public void endDocument ()
throws SAXException
{
// 结束解析文档,即解析根元素结束标签时调用该方法
}
/**
* Receive notification of the end of a Namespace mapping.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the end of
* each prefix mapping.</p>
*
* @param prefix The Namespace prefix being declared.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#endPrefixMapping
*/
public void endPrefixMapping (String prefix)
throws SAXException
{
// no op
}
/**
* Receive notification of the start of an element.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the start of
* each element (such as allocating a new tree node or writing
* output to a file).</p>
*
* @param uri The Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace
* processing is not being performed.
* @param localName The local name (without prefix), or the
* empty string if Namespace processing is not being
* performed.
* @param qName The qualified name (with prefix), or the
* empty string if qualified names are not available.
* @param attributes The attributes attached to the element. If
* there are no attributes, it shall be an empty
* Attributes object.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#startElement
*/
public void startElement (String uri, String localName,
String qName, Attributes attributes)
throws SAXException
{
// 开始解析每个元素调用这个方法
}
/**
* Receive notification of the end of an element.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the end of
* each element (such as finalising a tree node or writing
* output to a file).</p>
*
* @param uri The Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace
* processing is not being performed.
* @param localName The local name (without prefix), or the
* empty string if Namespace processing is not being
* performed.
* @param qName The qualified name (with prefix), or the
* empty string if qualified names are not available.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#endElement
*/
public void endElement (String uri, String localName, String qName)
throws SAXException
{
// 每个元素结束的时候都会调用该方法
}
/**
* Receive notification of character data inside an element.
*
* <p>By default, do nothing. Application writers may override this
* method to take specific actions for each chunk of character data
* (such as adding the data to a node or buffer, or printing it to
* a file).</p>
*
* @param ch The characters.
* @param start The start position in the character array.
* @param length The number of characters to use from the
* character array.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#characters
*/
public void characters (char ch[], int start, int length)
throws SAXException
{
// 解析到每个元素的内容时会调用此方法
}
}
public static void main(String[] args) throws Exception, Exception {
SAXParserFactory factory = SAXParserFactory.newInstance();
String path = TestSAX.class.getClassLoader().getResource("test.xml").getPath();
SAXParser saxParser = factory.newSAXParser();
MyHandler myHandler = new MyHandler("name");
saxParser.parse(path, myHandler);
List<Map<String, String>> list = myHandler.getList();
System.out.println(JSON.toJSONString(list));
}
开始解析 xml
开始解析 元素
正在解析每个元素内容
开始解析 元素
正在解析每个元素内容
开始解析 元素
正在解析每个元素内容
-----name zhangsan
元素内容 解析结束
正在解析每个元素内容
正在解析每个元素内容
开始解析 元素
正在解析每个元素内容
元素内容 解析结束
正在解析每个元素内容
开始解析 元素
正在解析每个元素内容
元素内容 解析结束
正在解析每个元素内容
元素内容 解析结束
正在解析每个元素内容
开始解析 元素
正在解析每个元素内容
开始解析 元素
正在解析每个元素内容
-----name xiangli
元素内容 解析结束
正在解析每个元素内容
正在解析每个元素内容
开始解析 元素
正在解析每个元素内容
元素内容 解析结束
正在解析每个元素内容
开始解析 元素
正在解析每个元素内容
元素内容 解析结束
正在解析每个元素内容
元素内容 解析结束
正在解析每个元素内容
元素内容 解析结束
文档解析 结束
[{"name":"zhangsan"},{"name":"xiangli"}]
3.JDOM解析
JDOM的API中大量使用了collections类,它自身不带有解释器,一般使用SAX解释器
public static void main(String[] args) {
String path = MyJDOM.class.getClassLoader().getResource("test1.xml").getPath();
try {
parserXML(path);
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//解析xml
public static void parserXML(String path) throws JDOMException, IOException {
SAXBuilder saxBuilder = new SAXBuilder();
Document build = saxBuilder.build(path);
Element root = build.getRootElement();
List<Element> children = root.getChildren("person");
for (Element element : children) {
List<Element> children2 = element.getChildren();
for (Element elem : children2) {
System.out.println(elem.getName()+":"+elem.getValue());
}
}
}
4.DOM4J解析
DOM4J的API是最复杂的,也是性能最好的,甚至就连sun公司也使用 DOM4j ,缺点就是可移植性太差
public static void main(String[] args) throws DocumentException {
InputStream resourceAsStream = MyDOM4J.class.getClassLoader().getResourceAsStream("test1.xml");
SAXReader saxReader = new SAXReader();
Document read = saxReader.read(resourceAsStream);
Element rootElement = read.getRootElement();
System.out.println("当前节点名称 :"+rootElement.getName());
listNodes(rootElement);
}
//遍历当前节点下的所有节点
public static void listNodes(Element node){
System.out.println("当前节点的名称:" + node.getName());
//首先获取当前节点的所有属性节点
List<Attribute> list = node.attributes();
//遍历属性节点
for(Attribute attribute : list){
System.out.println("属性"+attribute.getName() +":" + attribute.getValue());
}
//如果当前节点内容不为空,则输出
if(!(node.getTextTrim().equals(""))){
System.out.println( node.getName() + ":" + node.getText());
}
//同时迭代当前节点下面的所有子节点
//使用递归
Iterator<Element> iterator = node.elementIterator();
while(iterator.hasNext()){
Element e = iterator.next();
listNodes(e);
}
}
当前节点名称 :persons
当前节点的名称:persons
当前节点的名称:person
当前节点的名称:name
name:java小强
当前节点的名称:sex
sex:man
当前节点的名称:age
age:23