XML?
XML(EXtensible Markup Language),可扩展标记语言;
区别于java.util.Properties,将配置信息保存在“属性文件”中,以便读取和修改;(Properties文件下的属性-描述难以解析,与文本长度/格式有关)
XML的特点?
-
XML与操作系统、编程语言的开发平台都无关【通用的数据交换格式】
-
实现不同系统之间的数据交换【包括系统的配置文件】
-
是一种标记语言,没有固定的标记,可以随便发明也可以自己创建
-
【整个XML是一种树形文件】
XML有什么用?
- 数据交互
- 配置应用程序和网站
- Ajax基石
XML怎么写(结构是什么样)?
- 开头 - <?xml version="1.0"?> 【声明部分(位于第一行);这个是满足xml 1.0标准的】
- 文档类型定义 - <!DOCTYPE web-app PUBLIC ...>
- 正文(包括 根元素/其他元素/文本) - <A0> <A1>...</A1> <A0>
【底下的都是:文档元素描述信息(文档结构),所有带尖括号的都叫标签,也叫元素,都是用树形文件写出来的】
eg:
<?xml version="1.0" encoding="UTF-8"?>
<books> 【根元素,每个XML文件的根元素有且仅有一个】
<!--图书信息 --> 【XML中的注释语法:<!--……-->】
<book id="bk101"> 【books的子元素,包含关系的元素要用缩进来体现】
<author>王珊</author> 【book的子元素】
<title>.NET高级编程</title> 【就像以前的类和属性】
<description>包含C#框架和网络编程等</description>
</book>
<book id="bk102"> 【books的子元素】
<author>李明明</author>
<title>XML基础编程</title>
<description>包含XML基础概念和基本作用</description>
</book>
</books> 【根元素</……>是结束的符号】
XML的语法:
- 属性值用双引号包裹,eg:<book id="bk101">
- 一个元素可以有多个属性(或者叫子元素),eg:book元素下的<author><title><description>
- 属性值中不能直接包含<、“、&(不建议:‘、>)【最好都不要写】
XML写法小结:
- XML文档内容由一系列标签元素组成,XML必须正确的嵌套,所有XML元素都必须有结束标签(</……>);
- 根元素有且仅有一个;
- <元素名 属性名=“属性值”>元素内容</元素名>,同级标签以缩进对齐;
- XML标签对大小写敏感;
- 空元素的方法:
<name>(这里是一个空格)</name>
<name></name>
<name/> - 当元素中出现很多特殊字符时,可以使用CDATA节,如:<description><![CDATA[讲解了元素<title>以及</title>的使用]]> 等同于:<description><讲解了元素<title>以及</title>的使用> </description>
- 为解决命名冲突,采取了类似Java包 (com.myStudy.test) 的方式,即“命名空间 namespace”,eg:
<element xmlns:="namespace_URL01" >
<child xmlns:="namespace_URL02">
grand_children
</child>
more_children ...
</element>
元素命名习惯?
- 编写的元素名称要有描述性,元素名称可以包含字母、数字或其他的字符,元素名称不能以数字或者标点符号开始(<5name>是错误的);
- 名字尽量简短些,可以用下划线“_”,但是不要用中横线“-”、点“.”或者冒号“:”(<book_title>);
- 数据库怎么命名,XML文件就怎么命名,要保持一致;
XML解析?
要处理XML文档,先得要解析(parse)它;解析器:读入一个文件,确认这个文件有正确的格式,然后将其分解成各种元素,然后可以访问这些元素;
Java库提供了两种解析器:DOM和SAX;
解析XML的相关技术?
- DOM
基于XML文档树结构的解析(DOM把XML文档映射成一个倒挂的树,解析成DOM树放内存里)
适用于多次访问的XML文档
特点:比较消耗资源
DOM解析XML文件步骤?
- 创建解析器工厂对象
- 解析器工厂对象创建解析器对象
- 解析器对象指定XML文件创建Document对象
- 以Document对象为起点操作DOM树
eg:下面的“(读)写XML文件?”中给出了Document对象的使用示例;
- SAX
基于事件的解析,适用于大数据量的XML文档
特点:占用资源少,内存消耗小
- DOM4J(把DOM解析进行了一次封装,应用更多)
非常优秀的Java XML API;
性能优异、功能强大;
开放源代码;
XML与反射?
eg:web.xml的Servlet配置,读取xml文件,根据名称获取server下的子元素,通过ClassForName反射获取类信息,newInstance得到对象,invoke()调用对象方法;
定义一个接口,有a() b() c()3个方法;将其实现类放在xml的Servlet配置里面(类名、路径)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://www.example.org/web-app_2_5"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.org/web-app_2_5 web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>MyServer</servlet-name>
<servlet-class>com.oracle.demo04.PersonS</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServer</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
//test
@Test
public void fuc_02() throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, DocumentException {
//创建解析器
SAXReader sa = new SAXReader();
//此处写要读取xml文件的路径
Document doc = (Document) sa.read("testXML\\xml_01.xml");
//获取根元素<web-app>
Element el = doc.getRootElement();
//获取根元素下的指定的子元素
Element em = el.element("servlet");
//获取server下的子元素
String servletclass = em.elementText("servlet-class");
//获取后再根据获取到的xml元素来获取字节码对象
Class c = Class.forName(servletclass);
//创建一个对象,然后通过字节码对象来过去该类的方法
Object obj = c.newInstance();
Method a = c.getMethod("a");
Method b = c.getMethod("b");
Method c = c.getMethod("c");
//调用方法
a.invoke(obj);
b.invoke(obj);
c.invoke(obj);
//要注意,xml的路径一定要写对,创建doc对象读取的路径也要写对
}
(读)写XML文件?
对XML文件的元素“增删改查”;
eg:XML源文件
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<exam>
<student examid="111" idcard="123">
<name>张三</name>
<location>广州</location>
<grade>100</grade>
</student>
<student examid="444" idcard="333">
<name>李四</name>
<location>大连</location>
<grade>97</grade>
</student>
<student examid="1111111" idcard="22222">
<name>小毛</name>
<location>广州</location>
<grade>23.0</grade>
</student>
<student examid="199" idcard="300">
<grade>80.0</grade>
<location>广州</location>
<name>钟源茂</name>
</student>
</exam>
// test 用到getDocument()方法;删除和新增会用到writeXml(Document document),将内存数据保存至XML;如下所示:
// 获得操作xml文件的Document 对象
private static Document getDocument() throws ParserConfigurationException,
IOException, org.xml.sax.SAXException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File("testXML\\xml_03.xml"));
Element e = document.getDocumentElement();
return document;
}
// 将内存中的数据保存到XML文件中
private static void writeXml(Document document) throws TransformerException {
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(new File("testXML\\xml_03.xml"));
TransformerFactory factory = TransformerFactory.newInstance();
Transformer trans = factory.newTransformer();
trans.transform(source, result);
}
1.读XML-查找:获取Doucument对象(绑定XML文件),根据TagName查找获得List元素列表,遍历列表获取各个元素属性来一一匹配目标值,找到后封装属性于返回对象;
public Student fuc_03(String Find_examid) throws IOException, SAXException, ParserConfigurationException {
Document document = getDocument();
NodeList list = document.getElementsByTagName("student");
for (int i = 0; i < list.getLength(); i++) {
Element element = (Element) list.item(i);
String value = element.getAttribute("examid");
if (Find_examid.equals(value)) {//遍历所有节点找到索引examid元素,如果其值value匹配Find_examid,则封装属性到Student对象返回
Student student = new Student();
student.setExamid(Find_examid);
student.setIdcart(element.getAttribute("idcard"));
student.setName(element.getElementsByTagName("name").item(0).getTextContent());
student.setLocation(element.getElementsByTagName("location").item(0).getTextContent());
student.setGrade(element.getElementsByTagName("grade").item(0).getTextContent());
return student;
}
}
return null;
}
2.新增:获取Doucument对象(绑定XML文件),document.createElement创建元素与其子元素,setAttribute和setTextContent添加元素属性,appendChild将子元素与父元素"绑定"-将父元素与根元素绑定,writeXml写入XML;
@Test
public void fuc_04() throws ParserConfigurationException,
IOException, org.xml.sax.SAXException, TransformerException {
Student student = new Student("明凯", "4396", "666", "武汉", "99");//test
Document document = getDocument();//获得document对象
Element studentNode = document.createElement("student");//新建Element元素对象
studentNode.setAttribute("idcard", student.getIdcart());//设置“属性”值
studentNode.setAttribute("examid", student.getExamid());
Node name = document.createElement("name");//创建3个子Node并赋值
name.setTextContent(student.getName());
Node location = document.createElement("location");
location.setTextContent(student.getLocation());
Node grade = document.createElement("grade");
grade.setTextContent(student.getGrade());
// 将3个子元素添加到当前元素(绑定)
studentNode.appendChild(name);
studentNode.appendChild(location);
studentNode.appendChild(grade);
// 获取XML文档的根元素,将当前元素添加到其子元素列表中
Element root = document.getDocumentElement();
root.appendChild(studentNode);
writeXml(document); // 将Document写入XML
}
3.删除,获取Doucument对象(绑定XML文件),查找目标元素node(根1.查找一样),removeChild()从 “根元素”/其父元素的“父元素” 删除其父元素,writeXml写入XML;
// 如:根据name删除整个元素,即从name找到其“父元素”,从 “根元素”/其父元素的“父元素” 删除其父元素
@Test
public void fuc_05() throws ParserConfigurationException, IOException, TransformerException, org.xml.sax.SAXException {
String name = "钟源茂0";
Document document = getDocument();
NodeList list = document.getElementsByTagName("name");
for (int i = 0; i < list.getLength(); i++) {
Node node = list.item(i);
if (node.getTextContent().equals(name)) {
node.getParentNode().getParentNode().removeChild(node.getParentNode());//从当前name元素的父元素的“父元素” 删除其父元素
}
}
writeXml(document);
}
XPath定位?
通过遍历DOM树需要从根节点开始查找节点,XPath可以指定“路径”,让元素/属性的访问变得容易;使用方法类似打开文件的目录一样;可以指定元素/exam/student、元素下的属性/exam/student/name(子元素)、元素列表下的某一个/exam/student[7]/name(按照索引)
eg:
// 测试XPath
@Test
public void fuc_06() throws ParserConfigurationException, IOException, TransformerException, org.xml.sax.SAXException, XPathExpressionException {
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath path = xPathFactory.newXPath();
Document document = getDocument();//获得document对象
NodeList list = (NodeList) (path.evaluate("/exam/student/name", document, XPathConstants.NODESET));//满足指定路径Path的整个列表
for (int i = 0; i < list.getLength(); i++) {
System.out.println(list.item(i).getTextContent());
}
Node node_01 = (Node) (path.evaluate("/exam/student[1]/name", document, XPathConstants.NODE));//满足指定路径Path的第1个元素(从1开始)
System.out.println("node_01:"+node_01.getTextContent());
String node_02 = (String) (path.evaluate("/exam/student[2]/name", document, XPathConstants.STRING));//ke==可以直接转成String/int/boolean...
System.out.println("node_02:"+node_02);
}
流机制解析器?
DOM会完整的读入XML文档形成一个树形结构;如果文档太大,DOM的效率就不高,这种情况下就可以使用“流机制解析器”在运行时解析节点,如SAX解析器;
得到SAX解析器:SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
处理文档:saxParser.parse(source, handler); source是数据源(文件、URL、输入流);handler是处理器,为DefaultHandler类的对象(实现startElement方法);