XML语法和XML编程

2017/02/22 JavaEE

XML常见应用

XML技术除用于保存有关系的数据之外,它还经常用作软件配置文件,以描述程序模块之间的关系。
在一个软件系统中,为提高系统的灵活性,它所启动的模块通常由其配置文件决定

XML语法

一个XML文件分为如下几部分内容:

  • 文档声明
    • <?xml version="1.0" encoding="GB2312" standalone="yes" ?>
    • standalone属性说明文档是否独立,即是否依赖于其他的文档
  • 元素
    • XML元素指XML文件中出现的标签,一个标签分为开始标签和结束标签,一个标签有如下几种书写形式,例如: + 包含标签体:<a>www.xpress.cn</a> + 不含标签体的:<a></a>, 简写为:<a/> + 由于在XML中,空格和换行都作为原始内容被处理,所以,在编写XML文件时,使用换行和缩进等方式来让原文件中的内容清晰可读的“良好”书写习惯可能要被迫改变。 + 一个XML元素可以包含字母、数字以及其它一些可见字符,但必须遵守下面的一些规范 * 区分大小写 * 不能以数字或”_” (下划线)开头 * 不能以xml(或XML、或Xml 等)开头 * 不能包含空格。 * 名称中间不能包含冒号(:)
  • 属性
    • <input name=”text”>
    • 属性值一定要用双引号(”)或单引号(’)引起来
    • 定义属性必须遵循与标签相同的命名规范
    • 在XML技术中,标签属性所代表的信息,也可以被改成用子元素的形式来描述
  • 注释
  • CDATA区、特殊字符
    • 把这内容放在CDATA区里,对于CDATA区域内的内容,XML解析程序不会处理,而是直接原封不动的输出。
<![CDATA[
    <xpress>
        <br/>
    </xpress>
]]>
特殊字符 替代符号
& & amp;
< & lt;
> & gt;
& quot;
& apos;
  • 处理指令,简称PI (processing instruction)
    • 处理指令必须以“<?”作为开头,以“?>”作为结尾,XML声明语句就是最常见的一种处理指令。
    • 例如,在XML文档中可以使用xml-stylesheet指令,通知XML解析引擎,应用css文件显示xml文档内容。 + <?xml-stylesheet type="text/css" href="1.css"?>

XML约束

在XML技术里,可以编写一个文档来约束一个XML文档的书写规范,这称之为XML约束。

常用的约束技术

  • XML DTD
  • XML Schema

DTD约束

DTD约束即可以作为一个单独的文件编写,也可以在XML文件内编写。

在XML文件内编写

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE 书架 [
    <!ELEMENT 书架 (书+)>
    <!ELEMENT 书 (书名,作者,售价)>
    <!ELEMENT 书名 (#PCDATA)>
    <!ELEMENT 作者 (#PCDATA)>
    <!ELEMENT 售价 (#PCDATA)>
]>
<书架>
    <书>
        <书名>Java就业培训教程</书名>
        <作者>张孝祥</作者>
        <售价>39.00元</售价>
    </书>
    ...
</书架>

引入

  • 当引用的文件在本地时,采用如下方式
<!DOCTYPE 文档根结点 SYSTEM "DTD文件的URL">
<!DOCTYPE 书架 SYSTEM “book.dtd”> 在xml文件中手写一下。
  • 当引用的文件是一个公共的文件时,采用如下方式
<!DOCTYPE 文档根结点 PUBLIC "DTD名称" "DTD文件的URL">
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

元素定义

语法格式
<!ELEMENT 元素名称 元素类型>

元素类型可以是元素内容、或类型

  • 如为元素内容:则需要使用()括起来,如
    • <!ELEMENT 书架 (书名,作者,售价)>
    • <!ELEMENT 书名 (#PCDATA)>
  • 如为元素类型,则直接书写,DTD规范定义了如下几种类型:
    • EMPTY:用于定义空元素,例如<br/> <hr/>
    • ANY:表示元素内容为任意类型。
元素内容

元素内容中可以使用如下方式,描述内容的组成关系

  • 用逗号分隔,表示内容的出现顺序必须与声明时一致
<!ELEMENT 书架 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
  • |分隔,表示任选其一,即多个只能出现一个
<!ELEMENT MYFILE (TITLE|AUTHOR|EMAIL)>
  • 元素内容使用空白符分隔,表示出现顺序没有要求
<!ELEMENT MYFILE (TITLE AUTHOR EMAIL)>

在元素内容中也可以使用+、*、?等符号表示元素出现的次数

  • +: 一次或多次 (书+)
  • ?: 0次或一次 (书?)
  • *: 0次或多次 (书*)

也可使用圆括号( )批量设置

<!ELEMENT MYFILE ((TITLE*, AUTHOR?, EMAIL)* | COMMENT)>

属性定义

语法格式
<!ATTLIST 元素名  
    属性名1 属性值类型 设置说明  
    属性名2 属性值类型 设置说明  
    ……  
>
设置说明
  • #REQUIRED:必须设置该属性
  • #IMPLIED:可以设置也可以不设置
  • #FIXED:说明该属性的取值固定为一个值,在 XML 文件中不能为该属性设置其它值。但需要为该属性提供这个值
  • 直接使用默认值:在 XML 中可以设置该值也可以不设置该属性值。若没设置则使用默认值。
<!ATTLIST 页面作者  
     姓名 CDATA #IMPLIED  
     年龄 CDATA #IMPLIED  
     联系信息 CDATA #REQUIRED  
     网站职务 CDATA #FIXED "页面作者"  
     个人爱好 CDATA "上网"  
>
常用属性值类型
  • CDATA
    • 表示属性值为普通文本字符串。
  • ENUMERATED
    • 属性的类型可以是一组取值的列表,在 XML 文件中设置的属性值只能是这个列表中的某个值(枚举)
<?xml version = "1.0" encoding="GB2312" standalone="yes"?>
<!DOCTYPE 购物篮 [
    <!ELEMENT 肉 EMPTY>
    <!ATTLIST 肉 品种 ( 鸡肉 | 牛肉 | 猪肉 | 鱼肉 ) "鸡肉">
]>
<购物篮>
    <肉 品种="鱼肉"/>
    <肉 品种="牛肉"/>
    <肉/>
</购物篮>
  • ID
    • 表示属性的设置值为一个唯一值。
    • ID 属性的值只能由字母,下划线开始,不能出现空白字符
<?xml version = "1.0" encoding="GB2312" ?>

<!DOCTYPE 联系人列表[
    <!ELEMENT 联系人列表 ANY>
    <!ELEMENT 联系人(姓名,EMAIL)>
    <!ELEMENT 姓名(#PCDATA)>
    <!ELEMENT EMAIL(#PCDATA)>
    <!ATTLIST 联系人 编号 ID #REQUIRED>
]>

<联系人列表>
    <联系人 编号="1">
        <姓名>张三</姓名>
        <EMAIL>zhang@it315.org</EMAIL>
     </联系人>
    <联系人 编号="1">
        <姓名>李四</姓名>
        <EMAIL>li@it315.org</EMAIL>
    </联系人>
</联系人列表>
  • ENTITY(实体)

实体定义

实体用于为一段内容创建一个别名,以后在XML文档中就可以使用别名引用这段内容了。

实体可分为两种类型:引用实体和参数实体。

引用实体
语法格式
<!ENTITY 实体名称 “实体内容” >:直接转变成实体内容
引用方式
&实体名称;

应用:

<!ENTITY copyright “I am a programmer">
<!-- 在xml中直接引用 -->
<data>
&copyright;
</data>
参数实体
语法格式
<!ENTITY % 实体名称 "实体内容" >
引用方式
%实体名称;

应用:

<!ENTITY % TAG_NAMES "姓名 | EMAIL | 电话 | 地址">

<!ELEMENT 个人信息 (%TAG_NAMES; | 生日)>
<!ELEMENT 客户信息 (%TAG_NAMES; | 公司名)>

<!ENTITY % common.attributes
     " id ID #IMPLIED
    account CDATA #REQUIRED "
>
...
<!ATTLIST purchaseOrder %common.attributes;>
<!ATTLIST item %common.attributes;>

Schema约束

XML Schema 也是一种用于定义和描述 XML 文档结构与内容的模式语言,其出现是为了克服 DTD 的局限性

一个XML Schema文档通常称之为模式文档(约束文档),遵循这个文档书写的xml文件称之为实例文档。

名称空间

在XML Schema中,每个约束模式文档都可以被赋以一个唯一的名称空间,名称空间用一个唯一的URI(Uniform Resource Identifier,统一资源标识符)表示。 在Xml文件中书写标签时,可以通过名称空间声明(xmlns),来声明当前编写的标签来自哪个Schema约束文档

注意:名称空间的名字语法容易让人混淆,尽管以 http:// 开始,那个 URL 并不指向一个包含模式定义的文件。事实上,这个 URL:http://www.xpress.cn根本没有指向任何文件,只是一个分配的名字。

  • targetNamespace元素用于指定schema文档中声明的元素属于哪个名称空间。
  • elementFormDefault元素用于指定,该schema文档中声明的根元素及其所有子元素都属于targetNamespace所指定的名称空间。

使用名称空间引入Schema

schemaLocation此属性有两个值。第一个值是需要使用的命名空间。第二个值是供命名空间使用的 XML schema 的位置,两者之间用空格分隔。

注意:在使用schemaLocation属性时,也需要指定该属性来自哪里。

<?xml version="1.0" encoding="UTF-8" ?>
<!-- targetNamespace="http://www. xpress.cn" 绑定名称空间-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www. xpress.cn"
        elementFormDefault="qualified">
    <xs:element name='书架' >
        <xs:complexType>
            <xs:sequence maxOccurs='unbounded' >
                <xs:element name='书' >
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name='书名' type='xs:string' />
                            <xs:element name='作者' type='xs:string' />
                            <xs:element name='售价' type='xs:string' />
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>
<?xml version="1.0" encoding="UTF-8"?>

<!-- xmlns:xpress="http://www.xpress.cn" 约束文档的名称空间 -->
<!-- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 指定xsi的名字空间,因为是w3c的名字空间,解析器会内置 -->
<!-- xsi:schemaLocation=“http://www.xpress.cn book.xsd" 指定xsi的schemaLocation属性 -->
<!-- xsi:schemaLocation="http://www.xpress.cn book.xsd http://www.xpress.cn note.xsd"引入多个使用空格分割 -->
<!-- xmlns:xpress 如果省略冒号和后面的xpress则使用默认名字空间,则下面的元素和也省略xpress:使用默认名字空间 -->
<xpress:书架 xmlns:xpress="http://www.xpress.cn"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://www.xpress.cn book.xsd http://www.xpress.cn note.xsd">

    <xpress:>
        <xpress:书名>JavaScript网页开发</xpress:书名>
        <xpress:作者>张孝祥</xpress:作者>
        <xpress:售价>28.00元</xpress:售价>
    </xpress:书>
</xpress:书架>

多个名称空间一起引用

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

<书架 xmlns="http://www.it315.org/xmlbook/schema" 
    xmlns:demo="http://www.it315.org/demo/schema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.it315.org/xmlbook/schema                 http://www.it315.org/xmlbook.xsd 
        http://www.it315.org/demo/schema http://www.it315.org/demo.xsd">
    <书>
        <书名>Java网页开发</书名>
        <作者>xpress</作者>
        <售价 demo:币种=”人民币”>21.00元</售价>
    </书>
</书架>

不使用名称空间引入文档

xsi:noNamespaceSchemaLocation="xmlbook.xsd"

Schema语法

参看w3school

XML Schema 与 DTD比较

  • XML Schema符合XML语法结构。
  • DOM、SAX等XML API 很容易解析出 XML Schema 文档中的内容。
  • XML Schema对名称空间支持得非常好。
  • XML Schema比XML DTD支持更多的数据类型,并支持用户自定义新的数据类型。
  • XML Schema定义约束的能力非常强大,可以对XML实例文档作出细致的语义限制。
  • XML Schema不能像DTD一样定义实体,比DTD更复杂,但Xml Schema现在已是w3c组织的标准,它正逐步取代DTD。

XML编程

XML解析方式分为两种:dom和sax

  • DOM:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种方式。
    • 解析器 Crimson、Xerces 、Aelfred2
  • SAX:(Simple API for XML) 不是官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。
    • 开发包 Jaxp、Jdom、dom4j
  • StAX 框架(Streaming API for XML)
    • StAX 框架出现于 Java SE 6 中,它的设计目标就是要结合 SAX 框架和 DOM 框架的优点。既要求运行时效率,也要求保持元素的上下文状态。

状态保持能力则依次 SAX -> StAX -> DOM 变强
解析速度按 SAX -> StAX -> DOM 依次变慢

DOM解析和JAX解析比较

  • DOM解析会加载整个XML后在内存中生成一个Document对象
    • 缺点:使用dom解析xml文档,如果文件比较大,对内存消耗就特别大,极容易导致内存溢出,所以dom方式不适合操作大的xml文档。
    • 优点:实现crud特别方便,操作速度也比较快。
  • SAX方式读取一行处理一行
    • 缺点:只适合查找数据,不适合作增删改操作
    • 优点:解析速度快、对内存占用少,查找数据特别方便

JAXP DOM解析

DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点)。

  • 位于一个节点之上的节点是该节点的父节点(parent)
  • 一个节点之下的节点是该节点的子节点(children)
  • 同一层次,具有相同父节点的节点是兄弟节点(sibling)
  • 一个节点的下一个层次的节点集合是节点后代(descendant)
  • 父、祖父节点及所有位于节点上面的,都是节点的祖先(ancestor)

Node对象

  • Node对象提供了一系列常量来代表结点的类型,当开发人员获得某个Node类型后,就可以把Node节点转换成相应的节点对象(Node的子类对象),以便于调用其特有的方法。
  • Node对象提供了相应的方法去获得它的父结点或子结点。编程人员通过这些方法就可以读取整个XML文档的内容、或添加、修改、删除XML文档的内容了。

使用DOM解析XML

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<书架>
    <书 name="book">
        <售价>111</售价>
        <书名>Java教程</书名>
        <作者>xpress</作者>
    </书>
</书架>
/**使用jaxp操作xml文档
 * @param args
 * @throws ParserConfigurationException
 * @throws IOException
 * @throws SAXException
 */
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
    //1.获取工厂
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    //2.产生解析器
    DocumentBuilder builder = factory.newDocumentBuilder();
    //3.解析xml文档,得到代表文档的document
    Document document = builder.parse(new File("src/book.xml"));
    //遍历
    list(document);
}

//得到售价结点的值
public void read() throws Exception{
    //1.获取工厂
    Document document = getDocument();

    NodeList list = document.getElementsByTagName("售价");
    Node price = list.item(0);
    String value = price.getTextContent();
    System.out.println(value);
    price.setTextContent("109");

    //把内存中的document写到xml文档
    writeDocument(document);
}

//向指定节点中增加孩子节点(售价节点)
public void add() throws Exception{
    Document document = getDocument();

    //创建需要增加的节点
    Node price = document.createElement("售价");
    price.setTextContent("59元");
    //得到需要增加的节点的父亲
    Node parent = document.getElementsByTagName("书").item(0);
    //把需要增加的节点挂到父结点上
    parent.appendChild(price);

    writeDocument(document);

}

//向指定位置上插入售价节点
public void add2() throws Exception{
    Document document = getDocument();

    Node node = document.createElement("售价");
    node.setTextContent("39元");
    Node parent = document.getElementsByTagName("书").item(0);
    parent.insertBefore(node, document.getElementsByTagName("书名").item(0));

    writeDocument(document);
}

//删除xml文档的售价结点
public void delete() throws Exception{
    Document document = getDocument();

    Node node = document.getElementsByTagName("售价").item(2);
    node.getParentNode().removeChild(node);

    writeDocument(document);
}

//操作xml文档属性
public void updateAttribute() throws Exception{
    Document document = getDocument();

    //操作xml文档的元素时,一般都把元素当作node对象,但是程序员如果发现node不好使时,就应把node强转成相应类型
    Node node  = document.getElementsByTagName("书").item(0);
    Element book = null;
    if(node.getNodeType()==Node.ELEMENT_NODE){  //在作结点转换之前,最好先判断结点类型
        book  = (Element)node;
    }

    book.setAttribute("name", "xxxx");
    book.setAttribute("password", "123");
    book.removeAttribute("password");

    writeDocument(document);
}

public void writeDocument(Document document){
    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer ts = tf.newTransformer();
    ts.transform(new DOMSource(document), new StreamResult(new File("src/book.xml")));
}

public document getDocument(){
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document document = builder.parse(new File("src/book.xml"));
    return document;
}

//遍历
public static void list(Node node){
    if(node.getNodeType()==Node.ELEMENT_NODE){
        System.out.println(node.getNodeName());
    }
    NodeList list = node.getChildNodes();
    for(int i=0;i<list.getLength();i++){
        Node child = list.item(i);
        list(child);
    }
}

JAXP SAX解析

SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。

SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器

解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。

SAX解析

使用SAX解析XML

/**
 *sax方式解析xml文件
 * @throws SAXException
 * @throws ParserConfigurationException
 * @throws IOException
 */
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
    //1.创建工厂
    SAXParserFactory factory = SAXParserFactory.newInstance();
    //2.用工厂创建解析器
    SAXParser sp = factory.newSAXParser();
    //3.利用解析器得到reader
    XMLReader reader = sp.getXMLReader();
    //4、在解析xml文档之前,设置好事件处理器
    reader.setContentHandler(new MyContentHandler2());
    //4.利用reader读取 xml文档
    reader.parse("src/book.xml");
}

//实现ContentHandler接口
//得到xml文档内容的事件处理器
class MyContentHandler implements ContentHandler{

    public void startElement(String uri, String localName, String name,
            Attributes atts) throws SAXException {

        System.out.println("当前解析到了:" + name + ",这个标签是开始标签");
        for(int i=0;i<atts.getLength();i++){
            String attname = atts.getQName(i);
            String attvalue = atts.getValue(i);
            System.out.println(attname + "=" + attvalue);
        }
    }

    public void endElement(String uri, String localName, String name)
    throws SAXException {
        System.out.println("当前解析到了:" + name + ",这个标签是结束标签");
    }

    public void characters(char[] ch, int start, int length) throws SAXException {
        System.out.println("当前解析到了内容:" + new String(ch,start,length));
    }

    public void endDocument() throws SAXException {}

    public void endPrefixMapping(String prefix) throws SAXException {}

    public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {}

    public void processingInstruction(String target, String data) throws SAXException {}

    public void setDocumentLocator(Locator locator) {}

    public void skippedEntity(String name) throws SAXException {}

    public void startDocument() throws SAXException {}

    public void startPrefixMapping(String prefix, String uri)throws SAXException {}
}

//继承DefaultHandler类
class MyContentHandler2 extends DefaultHandler{

    private boolean isOk = false;
    private int index = 1;
    @Override
    public void characters(char[] ch, int start, int length)throws SAXException {
        if(isOk==true && index==1){
            System.out.println(new String(ch,start,length));
        }
    }

    @Override
    public void startElement(String uri, String localName, String name,Attributes attributes) 
            throws SAXException {
        if(name.equals("售价")){
            isOk = true;
        }
    }

    @Override
    public void endElement(String uri, String localName, String name)throws SAXException {
        if(name.equals("售价")){
            isOk = false;
            index++;
        }
    }
}

StAX解析

XMLEventReader就像是一根绳子,拽一下,解析一个元素,产生一个事件。于是这种技术也被称为”Pull Parser”技术。
StAX 在处理 XML 文件时,产生的所有事件是通过一个 Iterator(XMLEventReader继承了 Iterator)返回的。应用程序通过这个 Iterator能知道某个解析事件的前后分别是什么。这类信息就是一个元素的上下文信息。

XMLInputFactory inputFactory = XMLInputFactory.newInstance();
InputStream input = new ByteArrayInputStream(
        ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                "<work-contact-info>" +
                "<Location>Shanghai-shuion-333</Location>" +
                "<Postal>200020</Postal>" +
                "<Tel><fix>63262299</fix><mobile>" +
                "1581344454</mobile></Tel>" +
                "<Appellation>Mr. Wang</Appellation>" +
                "</work-contact-info>").getBytes());
try {
    XMLEventReader xmlEventReader = inputFactory.createXMLEventReader(input);
    while (xmlEventReader.hasNext()) {
        XMLEvent event = xmlEventReader.nextEvent();

        if (event.isStartElement()) {
            StartElement startElement = event.asStartElement();
            System.out.println(startElement.getName().toString());
        }

        if (event.isCharacters()) {
            Characters text = event.asCharacters();
            if (!text.isWhiteSpace()) {
                System.out.println("\t" + text.getData());
            }
        }
    }
} catch (XMLStreamException e) {
    e.printStackTrace();
}

dom4j解析

Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。

DOM4j中,获得Document对象的方式有三种:

  • 读取XML文件,获得document对象
SAXReader reader = new SAXReader();
Document document = reader.read(new File("input.xml"));
  • 解析XML形式的文本,得到document对象
String text = "<members></members>";
Document document = DocumentHelper.parseText(text);
  • 主动创建document对象
Document document = DocumentHelper.createDocument();//创建根节点
Element root = document.addElement("members");

Xpath

Xpath教程

使用dom4j解析XML

book.xml

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

<书架>
  <书 name="yyyyyyy">
    <售价>209元</售价>
    <售价>19元</售价>
    <书名>Java就业培训教程</书名>
    <作者>张孝祥</作者>
    <售价>19元</售价>
    <售价>19元</售价>
  </书>  
  <书>
    <书名>JavaScript网页开发</书名>  
    <作者>张孝祥</作者>  
    <售价>28.00元</售价>
  </书>
</书架>

public void operate() throws Exception{
    SAXReader reader = new SAXReader();
    Document document = reader.read(new File("src/book.xml"));

    Element root = document.getRootElement();
    Element bookname = root.element("书").element("书名");
    System.out.println(bookname.getText());
    // read attr
    String value = root.element("书").attributeValue("name");
    System.out.println(value);
    // new
    Element price = DocumentHelper.createElement("售价");
    price.setText("19元");
    // add
    document.getRootElement().element("书").add(price);
    // add accurately
    List list = document.getRootElement().element("书").elements();
    list.add(1, price);
    // modify
    Element price1 = (Element) document.getRootElement().element("书").elements("售价").get(1);
    price1.setText("209元");
    // delete
    Element price2 = (Element) document.getRootElement().element("书").elements("售价").get(0);
    price2.getParent().remove(price2);
    // format
    OutputFormat format = OutputFormat.createPrettyPrint();
    format.setEncoding("UTF-8");
    // write
    XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
    writer.write(document);  //utf-8
    writer.close();
}
// Xpath
public void findUser() throws Exception{
    String username = "aaa";
    String password = "1233";

    SAXReader reader = new SAXReader();
    Document document = reader.read(new File("src/users.xml"));

    Element e = (Element) document.selectSingleNode("//user[@username='"+username+"' and @password='"+password+"']");
    if(e!=null){
        System.out.println("让用户登陆成功!!");
    }else{
        System.out.println("用户名和密码不正确!!");
    }

}

XStream

XStream映射

public class Province {
    private String name;
    private List<City> cityList;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<City> getCityList() {
        return cityList;
    }

    public void setCityList(List<City> cityList) {
        this.cityList = cityList;
    }
}

public class City {
    private String name;
    private String description;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

static Province getProvince() {
    Province province = new Province();

    province.setName("吉林");
    List<City> cityList = new ArrayList<City>();
    City city1 = new City();
    city1.setName("长春");
    city1.setDescription("吉林长春");
    cityList.add(city1);
    City city2 = new City();
    city2.setName("四平");
    city2.setDescription("吉林四平");
    cityList.add(city2);

    province.setCityList(cityList);
    return province;
}

public static void main(String[] args) {
    XStream xStream = new XStream();
    xStream.alias("省", Province.class);// 映射别名
    xStream.alias("市", City.class);
    xStream.aliasField("名称", City.class, "name");// field别名
    xStream.addImplicitCollection(Province.class, "cityList");// 不映射List集合
    xStream.useAttributeFor(Province.class, "name");// 设置属性
    xStream.aliasAttribute(Province.class, "name", "名称");// 属性别名
    xStream.omitField(City.class, "description");// 不映射字段
    String xml = xStream.toXML(getProvince());
    System.out.println(xml);
}

// <省 名称="吉林">
//   <市>
//     <名称>长春</名称>
//   </市>
//   <市>
//     <名称>四平</名称>
//   </市>
// </省>

XStream解析出现双下划线问题

XStream xstream = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")))
// 另直接调用xstream.toXML()方法,不要使用xstream.marshal(Object obj, HierarchicalStreamWriter writer)传入CompactWriter

以上概念总结于传智播客Java基础课程

Search

    Post Directory