侧边栏壁纸
  • 累计撰写 57 篇文章
  • 累计创建 10 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

3、XML

yilee
2023-04-04 / 0 评论 / 0 点赞 / 72 阅读 / 0 字
温馨提示:
本文最后更新于2024-05-31,若内容或图片失效,请留言反馈。 部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

三、XML

3.1 XML 概述

  • HTML 和XML 同宗同源,但是两者之间存在着重要的区别
    • 与HTML 不同, XML 是大小写敏感的。例如,<H1><hl>是不同的XML 标签。
    • 在HTML 中,如果从上下文中可以分清哪里是段落或列表项的结尾,那么结束标签(如</p></li> ) 就可以省略,而在XML 中结束标签绝对不能省略。
    • 在XML 中,只有单个标签而没有相对应的结束标签的元素必须以/ 结尾,比如<imgsrc="coffeecup.png” /> 。这样,解析器就知道不需要查找</img> 标签了。
    • 在XML 中,属性值必须用引号括起来。在HTML 中,引号是可有可无的。例如,<applet code="MyApplet.class" width=300 height=300> 对HTML 来说是合法的,但是对XML 来说则是不合法的。在XML 中,必须使用引号, 比如, width=“300” 。
    • 在HTML 中,属性名可以没有值。例如,< input type=“radio” name=“language” value=“Java” checked>` 。在XML 中,所有属性必须都有属性值。比如, checked=“true” 或checked="checked” 。
  1. XML 文档的结构

    • XML 文档应当以一个文档头开始,文档头是可选的,但是强烈推荐你使用文档

      < ?xml version="1.0"?>
      // 或
      < ?xml version="1.0" encoding="UTF-8"?>
      
    • 文档头之后通常是文档类型定义,文档类型定义是确保文档正确的一个重要机制,但是它不是必需的。

      < ! DOffiPE web-app PUBLIC
      	"-//Sun Microsystems, Inc. //DTD Web Application 2.2//EN"
      	"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
      
    • XML 文档的正文包含根元素,根元素包含其他元素。

      < ?xml version="1.0"?>
      <!DOCTYPE configuration ... >
      <configuration>
          <title>
              <font>
                  <name>Helvetica</name>
                  <size>36</size>
              </font>
          </title>
          ...
      </configuration>
      

      在设计XML 文档结构时,最好让元素要么包含子元素,要么包含文本,应该避免下面的情况:

      <font>
       Helvetica
       <size>36</size>
      </font>
      

      XML 元素可以包含属性,但是属性的灵活性要差很多。属性只应该用来修改值的解释,而不是用来指定值。如果你发现自己陷入了争论,在纠结千某个设置是否是对某个值的解释所作的修改,那么你就应该对属性说“不",转而使用元素,许多有用的文档根本就不使用属性。

    • 其他一些标记

      • 字符引用(character reference) 的形式是&#十进制值;或&#x 十六进制值;。

        &#233;&#xE9;
        
      • 实体引用(entity reference) 的形式是&name, 。

        &lt; &gt; &amp; &quot; &apos;
        <!-- 小千、大千、& 、引号、省略号 -->
        
      • CDATA 部分(CDATA Section) 用来限定其界限。

        <![CDATA[<&> are my favorite delimiters]]>
        <!-- 注意: CDATA 部分不能包含字符串"]]>" -->
        
      • 处理指令(processing instruction) 是那些专门在处理XML 文档的应用程序中使用的指令,它们由<? 和?>来限定其界限。

        < ?xm1-stylesheet href="mystyle.css" type="text/css"?>
        
      • 注释(comment) 用<!– 和 –>限定其界限。

3.2 解析XML 文档

  1. 两种XML 解析器

    • 像文档对象模型( Document Object Model, DOM ) 解析器这样的树型解析器( tree parser) ,它们将读入的XML 文档转换成树结构。
    • 像XML 简单API (Simple API for XML, SAX) 解析器这样的流机制解析器(streaming parser ) ,它们在读入XML 文档时生成相应的事件
  2. 使用步骤

    • 从DocumentBuilderFactory 中创建DocumentBuilder 对象

      DocumentBuilderFactory  factory = DocumentBuilderFactory.newInstance() ;
      DocumentBuilder builder = factory.newDocumentBuilder();
      
    • 从文件中读入某个文档

      // 用 file
      File f = ...
      Document doc = builder.parse(f);
      // 用一个URL
      URL u = ...
      Document doc = builder.parse(u);
      // 指定一个任意的输入流
      InputStream in = ...
      Document doc = builder.parse(in);
      
  3. Document 对象是XML 文档的树型结构在内存中的表示方式,它由实现了Node 接口及其各种子接口的类的对象构成。

    • 通过调用getDocumentElement 方法来启动对文档内容的分析,它将返回根元素。getTagName 方法可以返回元素的标签名。getChildNodes方法获得该元素的子元素,返回一个类型为Nodelist 的集合。Nodelist 类型中,item 方法将得到指定索引值的项,getLength 方法则提供了项的总数。

      Element root = doc.getDocumentElement();
      // root元素的标签名
      root.getTagName()
      // 获取 root 的子标签
      Nodelist children = root.getChildNodes()
      // 遍历所有子标签
      for (int i = 0; i < children.getLength(); i++) {
          Node child = children.itern(i);
          ...
      }
      

      ff6ee7975c4c4fb1862cac5b76db2a46

    • 分析子元素时要很仔细。如处理以下文档

      <font>
          <name>Helvetica</name>
          <size>36</size>
      </font>
      

      你预期font 有两个子元素,但是解析器却报告说有5 个:

      • 之间的空白字符

      • name 元素

      • 之间的空白字符

      • size 元素

      • 之间的空白字符

      DOM树如下

      aa8ea7a331864d7baa3746a4d14b5833

    • 若只需要子元素,则使用以下代码,这只会得到两个元素,它们的标签名是name 和size 。用getFirstChild 方法获取第一个元素,用getData 方法获取存
      储在Text 节点中的字符串。用getlastChild 方法得到最后一项子元素,用getNextSibling 得到下一个兄弟节点。

      for (int i = 0; i < children.getLength(); i++) {
          Node child = children.itern(i);
          if (child instanceof Element){
              Element childElement = (Element) child;
              // 获取它们包含的文本字符串
              Text textNode = (Text) childElement.getFirstChild();
              String text = textNode.getData().trim();
              ...
          }
      }
      
    • 枚举节点的属性,可以调用getAttributes 方法。它返回一个NamedNodeMap 对象,其中包含了描述属性的Node 对象。可以用和遍历Nodelist 一样的方式在NamedNodeMap中遍历各子节点。然后,调用getNodeName 和getNodeValue 方法可以得到属性名和属性值。

      NamedNodeMap attributes = element.getAttributes() ;
      for (int i= 0; i < attributes.getlength(); i++)
          Node attribute = attributes.item(i);
          String name = attribute.getNodeName();
          String value = attribute.getNodeValue();
      	...
      }
      // 如果知道属性名, 则可以直接获取相应的属性值:
      String unit = element.getAttribute("unit");
      
    • DOMTreeModel类实现了TreeModel 接口。getRoot 方法会返回文档的根元素, getChild 方法可以得到子元素的节点列表, 返回被请求的索引值对应的项。表的单元格渲染器显示了以下内容

      • 对元素,显示的是元素标签名和由所有的属性构成的一张表。
      • 对字符数据,显示的是接口( Text 、Comment 、CDATASection ) ,后面跟着数据,其中换行和回车字符被 \n 和 \r 取代。
      • 对其他所有的节点类型,显示的是类名,后面跟着toString 的结果。

3.3 验证XML 文档

  • 指定文档结构,可以提供一个文档类型定义(DTD) 或一个XML Schema 定义。

    <!-- DTD规则:一个font 元素必须总是有两个子元素,分别是name 和size 。 -->
    <!ELEMENT font (name, size)>
    <!-- 相同的Schema规则,但可以表达更加复杂的验证条件 -->
    <xsd:element name="font">
        <xsd:sequence>
            <xsd:element name="name" type="xsd:string"/>
            <xsd:element name="size" type="xsd:int"/>
        </xsd:sequence>
    </xsd:element>
    
  1. 文档类型定义

    • 提供DTD 的方式有多种。

      • 直接将其纳入到XML 文档中的DOCTYPE 声明中,位千由[ … ]限定界限的块中。文档类型必须匹配根元素的名字

        < ?xml version="1.0"?>
        <!DOCTYPE configuration [
        	<!ELEMENT configuration... >
        	more rules
        	...
        ]>
        <configuration>
            ...
        </configuration>
        
      • 把DTD 存储在外部会更具意义, SYSTEM 声明可以用来实现这个目标。指定一个包含DTD 的URL。

        <!DOCTYPE configuration SYSTEM "config.dtd">
        <!-- 或者 -->
        <!DOCTYPE configuration SYSTEM "http://myserver.com/config.dtd">
        
        1. 如果你使用的是DTD 的相对URL ( 比如“config . dtd” ) ,那么要给解析器一个File 或URL 对象,而不是InputStream 。如果必须从一个输入流来解析,那么请提供一个实体解析器

        2. 如果你使用的是DOM 解析器,并且想要支持PUBLIC 标识符,请调用DocumentBuilder 类的setEntityResolver 方法来安装EntityResolver 接口的某个实现类的一个对象。该接口只有一个方法: resolveEntity 。下面是一个典型实现的代码框架:

        class MyEntityResolver implements EntityResolver {
            @Override
            public InputSource resolveEntity(String publicID, String systemID) {
                if (publicID.equals(a known ID)) {
                    return new InputSource(DTD data);
                } else {
                    return null; // use default behavior
                }
            }
        
        }
        // 你可以从InputStream 、Reader 或宇符串中构建轮入源。
        
    • ELEMENT 规则

      42ac0d7a7ddf4a00841bc099ab6b57df

      <!-- menu 元素包含0 或多个item 元素 -->
      <!ELEMENT menu (item)*>
      <!-- font 是用一个name 后跟一个size 来描述的 -->
      <!ELEMENT font (name, size)>
      <!-- name 和 size 都包含文本 -->
      <!ELEMENT name (#PCDATA) >
      <!ELEMENT size (#PCDATA) >
      
    • 元素可以包含文本只有两种合法的情况

      • 该元素只包含文本

        <!ELEMENT name (#PCDATA)>
        
      • 该元素包含任意顺序的文本和标签的组合

        <!ELEMENT para (#PCDATA|em|strong|code)*>
        
        • 其他任何类型的包含#PCDATA 的规则都是不合法的。

          <!ELEMENT captionedImage (image, #PCDATA)>  
          
        • 在设计DTD 时,让其中所有的元素要么包含其他元素,要么只有文本

        • 在DTD 规则中并不能为元素指定任意的正则表达式, XML 解析器会拒绝某些导致非确定性的复杂规则,因为XML 标准允许解析器假设DTD 都是非二义性的。

    • 指定描述合法的元素属性的规则

      <!ATTLIST element attribute type default>
      
      • 合法的属性类型(type)

      75bf7e6d36df466092f153beb7b77057

      • CDATA 属性值的处理与你前面看到的对# PCDATA 的处理有着微妙的差别,并且与<![CDATA[…]> 部分没有多大关系。属性值首先被规范化,也就是说,解析器要先处理对字符和实体的引用(比如&#233 ; 或& lt; ),并且要用空格来替换空白字符。

      • NMTOKEN (即名字标记)与CDATA 相似, 但是大多数非字母数字字符和内部的空白字符是不允许使用的,而且解析器会删除起始和结尾的空白字符。NMTOKENS 是一个以空白字符分隔的名字标记列表。

      • ID 结构是很有用的, ID 是在文档中必须唯一的名字标记,解析器会检查其唯一性。IDREF 是对同一文档中已存在的ID 的引用,解析器也会对它进行检查。IDREFS 是以空白字符分隔的ID 引用的列表。

      • ENTITY 属性值将引用一个“未解析的外部实体” 。这是从SGML 那里沿用下来的,在实际应用中很少见到。DTD 也可以定义实体,或者定义解析过程中被替换的缩写。

        <!-- 实体定义 -->
        <!ENTITY back.label "Back">
        <!-- 引用实体,解析器会用替代字符串来替换该实体引用。 -->
        <menuitem label="&back.label;"/>
        
    • 属性默认值( default )

      344f0b61553f469786a0b957e4975658

      • 例子
      <!-- 描述了font 元素的style 属性,它有4 个合法的属性值,默认值是 plain -->
      <!ATTLIST font style (plain|bold|italic|bold-italic) "plain">
      <!-- size 元素的unit 属性可以包含任意的字符数据序列 -->
      <!ATTLIST size unit CDATA #IMPLIED>
      
    • 置你的解析器,解析DTD

      factory.setValidating(true);
      
      • 该工厂生成的所有文档生成器都将根据DTD 来验证它们的输入。验证的最大好处是可以忽略元素内容中的空白字符。
      <font>
          <name>Helvetica</name>
          <size>36</size>
      </font>
      
      • 一个不进行验证的解析器会报告font 、name 和size 元素之间的空白字符,但检查时会知道它们之间的空白字符不是文,就调用 factory.setlgnoringElementContentWhitespace(true); 这样生成器将不会报告文本节点中的空白字符。
    • 只要使用验证,就应该安装一个错误处理器,这需要提供一个实现了ErrorHandler 接口的对象。可以通过DocumentBuilder 类的setErrorHandler 方法来安装错误处理器

      builder.setErrorHandler(handler);
      
  2. XML Schema

    • 在文档中引用Schema 文件,用前缀xsd: 来表示XSL Schema 定义的命名空间。

      < ?xml version="1.0"?>
      <configuration xmIns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
      	xsi:noNamespaceSchemalocati on="config.xsd">
      </configuration>
      <!-- Schema文件config.xsd 会被用来验证该文档。 -->
      
    • Schema 为每个元素都定义了类型。类型可以是简单类型, 即有格式限制的字符串,或者是复杂类型。简单类型已内置,如下

      xsd:string
      xsd:int
      xsd:boolean
      <!-- 枚举类型 StyleType -->
      <xsd:simpleType name="StyleType">
          <xsd:restriction base="xsd:string">
              <xsd:enumeration value="PLAIN"/>
              <xsd:enumeration value="BOLD"/>
              <xsd:enumeration value="ITALIC"/>
              <xsd:enumeration value="BOLD_ITALIC"/>
          </xsd:restriction>
      </xsd:simpleType>
      
    • 定义元素时,要指定它的类型,类型约束了元素的内容。

      <xsd:element name="name" type="xsd:string"/>
      <xsd:element name="size" type="xsd:int"/>
      <!-- 例 --> <size> 10</size>
      <xsd:element name="style" type="StyleType"/>
      <!-- 例 --> <style>PLAIN</style>
      
    • 类型组合成复杂类型,FontType 是name 、size 和style 元素的序列,使用了ref属性来引用在Schema 中位千别处的定义。

      <xsd:complexType name="FontType">
          <xsd:sequence>
              <xsd:element ref="name"/>
              <xsd:element ref="size"/>
              <xsd:element ref="style"/>
          </xsd:sequence>
      </xsd:complexType>
      
    • 可以嵌套定义,xsd:sequence 结构和DTD 中的连接符号等价,而 xsd:choice 结构和I 操作符等价

      <xsd:complexType name="contactinfo">
          <xsd:choice>
              <xsd:element ref="email"/>
              <Xsd:element ref="phone"/>
          </xsd:choice>
      </xsd:complexType>
      <!-- 等价DTD "email|phone"  -->
      
    • 使用minoccurs 和maxoccurs 属允许重复元素

      <xsd:element name="item" type="..." minoccurs="0" maxoccurs="unbounded">
      <!-- 等价DTD "item*"  -->
      
    • 使用 xsd:attribute 指定属性

      <xsd:element name="size">
          <xsd:complexType>
              ...
              <xsd:attribute name="unit" type="xsd:string" use="optional" default="cm"/>
          </xsd:complexType>
      </xsd:element>
      <!-- 等价DTD "<!ATTLIST size unit CDATA #IMPLIED "cm">"  -->
      
    • 把Schema 的元素和类型定义封装在xsd:schema 元素中

      <xsd:schema xmIns:xsd="http://www.w3.org/2001/XMLSchema">
          ...
      </xsd:schema>
      
    • 解析带有Schema 的XML 文件,类似DTD但有不同

      • 必须打开对命名空间的支持,即使在XML 文件里你可能不会用到它。

        factory.setNamespaceAware(true);
        
      • 准备好处理Schema 的工厂

        final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
        final String W3_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
        factory.setAttribute (JAXP_SCHEMA_LANGUAGE , W3_XML_SCHEMA);
        
      • 解析器不会丢弃元素中的空白字符

  3. 实用示例(P142)swing实例

3.4 使用XPath 来定位信患

  1. XPath 语言使得访问树节点变得很容易。以下示例可以通过通过对XPath 表达式 /configuration/database/username 求值来得到database
    中的username 的值

    <configuration>
        ...
        <database>
            <username>dbuser</username>
            <password>secret</password>
            ...
        </database>
    </configuration>
    
  2. 使用Xpath 执行下列操作比普通的DOM 方式要简单得多

    • 获得文档节点。
    • 枚举它的子元素。
    • 定位database 元素。
    • 定位其子节点中名字为username 的节点。
    • 定位其子节点中的text 节点。
    • 获取其数据。
  3. XPath 可以描述XML 文档中的一个节点集,如/gridbag/row ,描述了根元素gridbag 的子元素中所有的row 元;使用[] 操作符来选择特定元素,如 /gridbag/row[1] 这表示的是第一行;使用@ 操作符可以得到属性值,如 /gridbag/row[1]/cell[1]/@anchor 描述了第一行第一个单元格的anchor 属性;/gridbag/row/cell/@anchor 描述了作为根元素gridbag 的子元素的那些row 元素中的所有单元格的anchor 属性节点。

  4. XPath 有很多有用的函数,如 count(/gridbag/row 返回gridbag 根元素的row 子元素的数量。

  5. 计算XPath 表达式

    // 从XPathFactory 创建一个XPath 对象
    XPathFactory xpfactory = XPathFactory.newInstance();
    path = xpfactory.newXPath();
    // 调用evaluate 方法来计算XPath 表达式,返回节点文本
    String username = path.evaluate("/configuration/database/username", doc) ;
    // 结果是多个节点
    NodeList nodes = (NodeList) path.evaluate("/gridbag/row", doc, XPathConstants.NODESET);
    // 结果只有一个节点
    Node node = (Node) path.evaluate("/gridbag/row[1]", doc, XPathConstants.NODE);
    // 结果是一个数字
    Number count = (Number) path.evaluate("count(/gridbag/row)", doc, XPathConstants.NUMBER);
    // 不必从文档的根节点开始搜索,可以从任意一个节点或节点列表开始。如果你有前一次计算得到的节点,那么就可以调用:
    result = path.evaluate(expression, node);
    

3.5 使用命名空间

  1. XML 的命名空间可以用千元素名和属性名。名字空间是由统一资源标识符( Uniform Resource Identifier, URI ) 来标识,HTTP 的URL 格式是最常见的标识符。注意, URL 只用作标识符字符串,而不是一个文件的定位符。在命名空间的URL 所表示的位置上不需要有任何文档, XML 解析器不会尝试去该处查
    找任何东西。

    http://www.w3.org/2001/XMLSchema
    uuid:lc759aed-b748-475c-ab68-10679700c4f2
    urn:com:books-r-us
    // 以下两个名字空间标识符,表示了不同的命名空间,尽管Web 服务器将为这两个URL 提供同一个文档。
    http://www.horstmann.com/corejava
    http://www.horstmann.com/corejava/index.html
    
  2. 有子元素继承了它们父元素的命名空间,而不带显式前缀的属性并不是命名空间的一部分。

    <configuration 
    	xmIns="http://www.horstmann.com/corejava"
    	xmIns:si ="http://www.bipm.fr/enus/3_ SI/si.html">
    	<size value= "210" si:unit="mm"/>
        ...
    </configuration>
    

    元素configuration 和size 是URI 为 http://www.horstmann.com/orejava 的命名空间的一部分。属性si: unit 是URI 为 http://www.bipm.fr/enus/3SI/si.html 的命名空间的一部分。然而,属性value 不是任何命名空间的一部分。

  3. 打开命名空间处理特性,调用DocumentBuilderFactory 类的setNamespaceAware 方法设置后,该工厂产生的所有生成器便都支持命名空间。

    factory.setNamespaceAware(true);
    

    节点有三个属性:

    • 带有前缀的限定名(qualified) ,由getNodeName 和getTagName 等方法返回。
    • 命名空间URI , 由getNamespaceURI 方法返回。
    • 不带前缀和命名空间的本地名( local name ) ,由getLocalName 方法返回。
  4. <xsd:schema xmIns:xsd="http://www.w3.org/2001/XMLSchema">
    <!-- 限定名 = xsd:schema -->
    <!-- 命名空间URI = http://www. w3. org/2001/XMLSchema -->
    <!-- 本地名 = schema -->
    

3.6 流机制解析器

  • DOM 解析器会完整地读入XML 文档,然后将其转换成一个树形的数据结构。但是,如果文档很大,并且处理算法又非常简单,可以在运行时解析节点, 而不必看到完整的树形结构,那么DOM 可能就会显得效率低下了。使用流机制解析器。
  1. 使用SAX 解析器

    • SAX 解析器在解析XML 输入数据的各个组成部分时会报告事件,但不会以任何方式存储文档,而是由事件处理器建立相应的数据结构。

      DOM 解析器是在SAX 解析器的基础上构建的,它在接收到解析器事件时构建DOM 树。

    • 在使用SAX 解析器时,需要一个处理器来为各种解析器事件定义事件动作。ContentHandler 接口定义了若干个在解析文档时解析器会调用的回调方法。

      • startElement 和endElement 在每当遇到起始或终止标签时调用。
      • characters 在每当遇到字符数据时调用。
      • startDocument 和endDocument 分别在文档开始和结束时各调用一次。
    • 例子

      <font>
          <name>Helvetica</name>
          <size units="pt">36</size>
      </font>
      // 解析器产生的回调
      // startElement, 元素名: font
      // startElement, 元素名: name
      // characters, 内容: Helvetica
      // endElement, 元素名: name
      // startElement, 元素名: size, 属性: units="pt"
      // characters, 内容: 36
      // endElement, 元素名: size
      // endElement, 元素名: font 
      
    • 构建SAX 解析器

      SAXParserFactory factory = SAXParserFactory.newInstance () ;
      SAXParser parser = factory.newSAXParser();
      // 处理文档,source 可以是一个文件、一个URL 字符串或者是一个输入流。
      // handler 属于DefaultHandler 的一个子类,为以下四个接口定义了空的方法:
      // ContentHandler
      // DTDHandler
      // EntityResolver
      // ErrorHandler
      parser.parse(source, handler);
      
    • startElement 方法有3 个描述元素名的参数,其中 qName 参数以 prefix:localName 的形式报告限定名。如果命名空间处理特性已经打开,那么 uri 和 localName 参数提供的就是命名空间和本地(非限定)名。

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

      与DOM 解析器一样,命名空间处理特性默认是关闭的,可以调用工厂类的setNamespaceAware 方法来激活命名空间处理特性

      SAXParserFactory factory = SAXParserFactory.newInstance();
      factory.setNamespaceAware(true);
      SAXParser saxParser = factory.newSAXParser();
      

      关闭自动下载验证文件

      factory.setFeature("http: //WWW.w3.org/TR/xhtml/DTD/xhtml-strict.dtd", false);
      
  2. 使用StAX 解析器

    • StAX 解析器是一种“拉解析器(pull parser )", 与安装事件处理器不同,你只需使用下面这样的基本循环来迭代所有的事件

      InputStream in = url.openStream() ;
      XMLInputFactory factory = XMLInputFactory.newInstance() ;
      XMLStreamReader parser= factory.createXMLStreamReader(in);
      while (parser.hasNext()) {
          int event = parser.next();
          // Call parser to to obtain event details
      }
      
    • 例子

      <font>
          <name>Helvetica</name>
          <size units="pt">36</size>
      </font>
      // 解析器将产生下面的事件
      // START_ELEMENT,元素名:font
      // CHARACTERS,内容:空白字符
      // START_ELEMENT,元素名:name
      // CHARACTERS,内容:Helvetica
      // END_ELEMENT,元素名:name
      // CHARACTERS,内容:空白字符
      // START_ELEMENT,元素名:size
      // CHARACTERS,内容:36
      // END_ELEMENT,元素名:size
      // CHARACTERS,内容:空白字符
      // END_ELEMENT,元素名:font
      
    • 要分析这些属性值,需要调用XMLStreamReader 类中恰当的方法

      // 获取当前元素的units 属性
      String units= parser.getAttributeValue(null, "units");
      

      默认情况下,命名空间处理是启用的,你可以通过像下面这样修改工厂来使其无效

      XMLInputFactory factory = XMLInputFactory.newInstance();
      factory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false);
      

3.7 生成XML 文档

  1. 不带命名空间的文档

    • 要建立一棵DOM 树,你可以从一个空的文档开始。通过调用DocumentBuilder 类的newDocument 方法可以得到一个空文档。

      Document doc = builder.newDocument () ;
      
    • 使用Document 类的createElement 方法可以构建文档里的元素

      Element rootElement = doc.createElement(rootName);
      Element childElement = doc.createElement(childName);
      
    • 使用createTextNode 方法可以构建文本节点

      Text textNode = doc.createTextNode(textContents);
      
    • 使用以下方法可以给文档添加根元素,给父结点添加子节点

      doc.appendChild(rootElement);
      rootElement.append(hild(childElement);
      childElement.appendChild(textNode);
      
    • 调用Element 类的setAttribute方法设置元素属性

      rootElement.setAttribute(name, value);
      
  2. 带命名空间的文档

    • 使用命名空间和上面的方法有差距,需要将生成器工厂设置为是命名空间感知的,然后再创建生成器

      DocumentBuilderFactoryfactory = DocumentBuilderFactory.newlnstance();
      factory.setNamespaceAware(true);
      builder = factory.newDocumentBuilder();
      
    • 使用createElementNS 而不是createElement 来创建所有节

      String namespace = "http://www.w3.org/2000/svg";
      Element rootElement = doc.createElementNS (namespace, "svg") ;
      
    • 如果节点具有带命名空间前缀的限定名,那么所有必需的带有xmlns 前缀的属性都会被自动创建。如果需要在HTML 中包含SVG, 那么就可以像下面这样构建元素

      Element svgElement = doc.createElement(namespace, "svg:svg")
      // 当该元素被写入XML 文件时,它会转变
      // <svg:svg xmlns:svg="http://www.w3.org/2000/svg">
      
    • 需要设置的元素属性的名字位千命名空间中,那么可以使用Element 类的setAttributeNS 方法

      rootElement.setAttributeNS(namespace, qualifiedName, value);
      
  3. 写出文档

    • 把DOM 树写出到输出流中

      • 第一种方式,为了将DOCTYPE节点纳入输出,我们还需要将SYSTEM和PUBLIC标识符设置为输出属性。
      // construct the do-nothing transformation
      Transformer t = TransformerFactory.newInstance().newTransformer() ;
      // set output properties to get a DOCTYPE node
      t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, systemldentifier);
      t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, publicldentifier);
      // set indentation
      t.setOutputPrope rty(OutputKeys.INDENT, "yes");
      t.setOutputProperty(OutputKeys.METHOD, "xml ");
      t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
      // apply the do-nothing transformation and send the output to a file
      t.transform(new DOMSource(doc), new StreamResult(new FileOutputStream(file)));
      
      • 第二种方式,使用LSSerializer 接口
      DOMImplementation impl = doc.getImplementation();
      DOMImplementationLS implLS = (DOMImplementationLS) impl.getFeature("LS", "3 .0");
      LSSerializer ser = implLS.createLSSerializer();
      // 需要空格和换行,可以设置下面的标志
      ser.getDomConfig().setParameter("format-pretty-print", true);
      // 将文档转换为字符串
      String str = ser.writeToString(doc);
      // 将输出直接写入到文件中
      LSOutput out = implLS.createLSOutput();
      out.setEncoding("UTF-8");
      out.setByteStream(Files.newOutputStream(path));
      ser.write(doc, out);
      
  4. 示例:生成SVG 文件(P172)

  5. 使用StAX 写出XML 文档

    • StAX API 使我们可以直接将XML 树写出,如下

      //从某个Output Stream 中构建一个XMLStreamWriter
      XMLOutputFactory factory = XMLOutputFactory.newInstance();
      XMLStreamWriter writer = factory.createXMLStreamWriter(out);
      // 产生XML 文件头
      writer.writeStartDocument()
      writer.writeStartElement(name);
      // 添加属性
      writer.writeAttribute(name, value);
      // 调用 writeStartElement 添加新的子节点
      // 写出字符
      writer.writeCharacters(text);
      // 在写完所有子节点之后调用以下方法关闭当前元素
      writer.writeEndElement();
      // 写出没有子节点的元素
      writer.writeEmptyElement(name);
      // 在文档的结尾调用以下方法关闭所有打开的元素。
      writer.writeEndDocurnent();
      

3.8 XSL 转换

  1. XSL 转换(X SLT) 机制可以指定将XML 文档转换为其他格式的规则,例如,转换为纯文本、XHTML 或任何其他的XML 格式。
  2. 将XML转化为其他格式必须提供XSLT 样式表,它描述了XML 文档向某种其他格式转换的规则。

54eb36d5af4f4237979d773fb9327df4

API注释

3.2 解析XML 文档

javax.xml.parsers.DocumentBuilderFactory 1.4

static DocumentBuilderFactorynewinstance()
// 返回DocumentBuilderFactory 类的一个实例。
DoeumentBuilder newDocumentBuilder()
// 返回DocumentBuilder 类的一个实例。

javax.xml.parsers.DocumentBuilder 1.4

Document parse(File f)
Document parse(String url)
Document parse(InputStream in)
// 解析来自给定文件、URL 或输入流的XML 文档,返回解析后的文档。

org.w3c.dom.Document 1.4

Element getDocumentElement()
// 返回文档的根元素。

org.w3c.dom. Element 1.4

String getTagName()
// 返回元素的名字。
String getAttribute(String name)
// 返回给定名字的属性值,没有该属性时返回空字符串。

rg.w3c.dom. Node 1.4**

Nodelist getChildNodes ()
// 返回包含该节点所有子元素的节点列表。
Node getFirstChild()
Node getlastChild()
// 获取该节点的第一个或最后一个子节点,在该节点没有子节点时返回null 。
Node getNextSibling()
Node getpreviousSibling()
// 获取该节点的下一个或上一个兄弟节点,在该节点没有兄弟节点时返回null 。
Node getparentNode()
// 获取该节点的父节点, 在该节点是文档节点时返回null 。
NamedNodeMap getAttributes ()
// 返回含有描述该节点所有属性的Attr 节点的映射表。
String getNodeName()
// 返回该节点的名字。当该节点是Attr 节点时,该名字就是属性名。
String getNodeValue()
// 返回该节点的值。当该节点是Attr 节点时,该值就是属性值。

org.w3c.dom. CharacterData 1.4

String getData()
// 返回存储在节点中的文本。

org.w3c.dom.NodeList 1.4

int getLength()
// 返回列表中的节点数。
Node item(int index)
// 返回给定索引值处的节点。索引值范围在0 到getlength() - 1 之间。

org.w3c.dom. NamedNodeMap 1.4

int getLength()
// 返回该节点映射表中的节点数。
Node item(int index)
// 返回给定索引值处的节点。索引值范围在0 到getlength()-1 之间。

3.3.1 文档类型定义

javax.xml.parsers.DocumentBuilder 1.4

void setEntityResolver(EntityResolver resolver)
// 设置解析器,来定位要解析的XML 文档中引用的实体。
void setErrorHandl er(ErrorHandl er handler)
// 设置用来报告在解析过程中出现的错误和警告的处理器。

org.xml.sax.EntityResolver 1.4

public InputSource resolveEntity(String publicID, String systemID)
// 返回一个输入源,它包含了被给定1D 所引用的数据,或者,当解析器不知道如何解析这个特定名字时,返回null 。如果没有提供公共ID , 那么参数publ icID 可以为null 。

org.xml.sax.InputSource 1.4

InputSource(InputStream in)
InputSource(Reader in)
InputSource(String system ID)
// 从流、读入器或系统ID (通常是相对或绝对URL ) 中构建输入源。

org.xml.sax. ErrorHandler 1.4

void fatalError(SAXParseException exception)
void error(SAXParseException exception)
void warning(SAXParseException exception)
// 覆盖这些方法以提供对致命错误、非致命错误和警告进行处理的处理器。

org.xml.sax.SAXParseException 1.4

int getlineNumber()
int getColumnNumber()
// 返回引起异常的巳处理的输入信息末尾的行号和列号。

javax.xml.parsers.DocumentBuilderFactory 1.4

boolean isValidating()
void setValidating(boolean value)
// 获取和设置工厂的validating 属性。当它设为true 时,该工厂生成的解析器会验证它们的输入信息。
boolean isIgnoringElementContentWhitespace()
void setlgnoringElementContentWhitespace(boolean value)
// 获取和设置工厂的ignoringElementContentWhitespace 属性。当它设为true时,该工厂生成的解析器会忽略不含混合内容( 即,元素与# PCDATA 混合)的元素节点之间的空白字符。

3.4 使用XPath 来定位信患

javax.xml.xpath.XPathFactory 5.0

static XPathFactory newinstance()
// 返回用于创建XPath 对象的XPathFactory 实例。
XPath newXpath()
// 构建用千计算XPath 表达式的XPath 对象。

javax.xml.xpath.XPath 5.0

String evaluate(String expression, Object startingPoint)
// 从给定的起点计算表达式。起点可以是一个节点或节点列表。如果结果是一个节点或节点集, 则返回的字符串由所有文本节点子元素的数据构成。
Object evaluate(String expression, Object startingPoint, QName returnType)
// 从给定的起点计算表达式。起点可以是一个节点或节点列表。resultType 是XPathConstants 类的常量STRING 、NODE 、NODESET 、NUMBER 或BOOLEAN 之一。返回值是String 、Node 、Nodel i st 、Number 或Boolean 。

3.5 使用命名空间

org.w3c.dom.Node 1.4

String getlocalName()
// 返回本地名(不带前缀),或者在解析器不感知命名空间时,返回null 。
String getNamespaceURI()
// 返回命名空间URI ,或者在解析器不感知命名空间时,返回null 。

javax.xml.parsers.DocumentBuilderFactory 1.4

boolean isNamespaceAware()
void setNamespaceAware(boolean value)
// 获取或设置工厂的namespaceAware 属性。当设为true 时,工厂产生的解析器是命名空间感知的。

3.6.1 使用SAX 解析器

javax.xml.parsers.SAXParserFactory 1.4

static SAXParserFactory newInstance()
// 返回SAXParserFactory 类的一个实例。
SAXParser newSAXParser()
// 返回SAXParser 类的一个实例。
boolean isNamespaceAware()
void setNamespaceAware(boolean value)
// 获取和设置工厂的namespaceAware 属性。当设为true 时,该工厂生成的解析器是命名空间感知的。
boolean isValidating()
void setValidating(boolean value)
// 获取和设置工厂的validating 属性。当设为true 时,该工厂生成的解析器将要验证其输入。

javax.xml.parsers.SAXParser 1.4

void parse(File f, DefaultHandler handler)
void parse(String url, DefaultHandler handler)
void parse(InputStream in, Defaul tHandl er handler)
// 解析来自给定文件、URL 或输入流的XML 文档,并把解析事件报告给指定的处理器。

org.xml.sax.ContentHandler 1.4

void startDocument()
void endDocument()
// 在文档的开头和结尾处被调用。
void startElement(String uri, String Iname, String qname, Attributes attr)
void endElement(String uri, String Iname, String qname)
// 在元素的开头和结尾处被调用。
// 参数: uri 命名空间的URI (如果解析器是命名空间感知的)
//		 Iname 不带前缀的本地名(如果解析器是命名空间感知的)
//		 qname 元素名(如果解析器是命名空间感知的),或者是带有前缀的限定名(如果解析器除了报告本地名之外还报告限定名)
void characters(char[] data, int start, int length)
// 解析器报告字符数据时被调用。
// 参数: data 字符数据数组
//		 start 在作为被报告的字符数据的一部分的字符数组中,第一个字符的索引
//		 length 被报告的字符串的长度

org.xml.sax.Attributes 1.4

int getLength ()
// 返回存储在该属性集合中的属性数量。
String getLocalName(int index)
// 返回给定索引的属性的本地名(无前缀),或在解析器不是命名空间感知的情况下返回空字符串。
Str i ng getURI(int index)
// 返回给定索引的属性的命名空间URI, 或者,当该节点不是命名空间的一部分,或解析器并非命名空间感知时返回空字符串。
String getQName(int index)
// 返回给定索引的属性的限定名(带前缀),或当解析器不报告限定名时返回空字符串。
String getValue(int index)
String getValue(String qname)
String getValue(String uri , String Iname)
// 根据给定索引、限定名或命名空间URI+本地名来返回属性值;当该值不存在时,返回null 。

3.6.2 使用StAX 解析器

javax.xml.stream.XMLInputFactory 6

static XMLinputFactory newInstance()
// 返回XML! nputF actory 类的一个实例。
void setProperty(String name, Object value)
// 设置这个工厂的属性,或者在要设置的属性不支持设置成给定值时,抛出IllegalArgumentException 。Java SE 的实现支持下列Boolean 类型的属性:
// 	"javax.xml.stream.isValidating 为false (默认值)时,不验证文档(规范不要求必须支持) 。
// 	"javax.xml.stream.isNamespaceAware" 为true (默认值)时,将处理命名空间(规范不要求必须支持) 。
// 	"javax.xml.stream.isCoalescing" 为false (默认值)时,邻近的字符数据不进行连接。
// 	"javax.xml.stream.isReplacingEntityReferences" 为true 默认值)时,实体引用将作为字符数据被替换和报告。
// 	"javax.xml.stream.isSupportingExtemalEntities" 为true (默认值)时,外部实体将被解析。规范对于这个属性没有给出默认值。
// 	"javax.xml.stream.supportDTD" 为true (默认值)时, DTD 将作为事件被报告。
XMLStreamReader createXMLStreamReader(InputStream in)
XMLStreamReader createXMLStreamReader(InputStream in , StringcharacterEncoding)
XMLStreamReader createXMLStreamReader(Reader in)
XMLStreamReader createXMLStreamReader(Source in)
// 创建一个从给定的流、阅读器或JAXP 源读入的解析器。

javax.xml.stream.XML StreamReader 6

boolean hasNext()
// 如果有另一个解析事件, 则返回true 。
int next()
// 将解析器的状态设置为下一个解析事件,并返回下列常量之一: START_ELEMENT END_ELEMENT CHARACTERS START_DOCUMENT END_DOCUMENT CDATA COMMENTSPACE(可忽略的空白字符) 、PROCESSING_INSTRUCTION ENTITY_REFERENCE DTD
boolean isStartElement ()
boolean isEndElement()
boolean isCharacters ()
boolean isWhiteSpace ()
// 如果当前事件是一个开始元素、结束元素、字符数据或空白字符, 则返回true 。
QName getName()
String getlocalName()
// 获取在START_ELEMENT 或END_ELEMENT 事件中的元素的名字。
String getText()
// 返回一个CHARACTERS 、COMMENT 或CDATA 事件中的字符,或一个ENTITY_REFERENCE的替换值,或者一个DTD 的内部子集。
int getAttributeCount()
QName getAttributeName(int index)
String getAttributeLocalName(int index)
String getAttributeValue(int index)
// 如果当前事件是START_ELEMENT , 则获取属性数量和属性的名字与值。
String getAttributeValue(String namespaceURI, String name)
// 如果当前事件是START_ELEMENT , 则获取具有给定名称的属性的值。如果namespaceURI为null , 则不检查名字空间。

3.7.4 示例:生成SVG 文件

javax.xml.parsers.DocumentBuilder 1.4

Document newDocument()
// 返回一个空文档。

org.w3c. dom.Document 1.4

Element createElement(String name)
Element createElementNS(String uri , String qname)
// 返回具有给定名字的元素。
Text createTextNode(String data)
// 返回具有给定数据的文本节点。

org.w3c.dom.Node 1.4

Node appendChild(Node chi 1 d)
// 在该节点的子节点列表中追加一个节点。返回被追加的节点。

org.w3c.dom.Element 1.4

void setAttribute(String name, String value)
void setAttributeNS(String uri, String qname, String value)
// 将有给定名字的属性设置为指定的值。
// 参数: uri 名字空间的URI 或null
//		 qname 限定名。如果有别名前缀,则uri 不能为null
//		 value 属性值

javax.xml.transform. TransformerFactory 1.4

static TransformerFactory newInstance()
// 返回TransformerFactory 类的一个实例。
Transformer newTransformer()
// 返回Transformer 类的一个实例,它实现了标识符转换(不做任何事情的转换) 。

javax.xml.transform.Transformer 1.4

void setOutputProperty(String name , String value)
// 设置输出属性。标准输出属性参见http : //www.w3.org/TR/xs lt#output , 其中最有用的几个如下示:
// 参数: doctype- publ i c DOCTYPE 声明中使用的公共ID
//		 doctype-system DOC TYPE 声明中使用的系统ID
//		 Indent "yes" 或者”no"
//		 method "xml"、"html" 、“text" 或定制的字符串
void transform(Source from , Result to)
// 转换一个XML 文档。

javax.xml.transform.dom.DOMSource 1.4

DOMSource(Node n)
// 从给定的节点中构建一个源。通常, n 是文档节点。

javax.xml.transform.stream.StreamResult 1.4

StreamResult(Fi le f)
StreamResult(OutputStream out)
StreamResult(Writer out)
StreamResult(String systemID)
// 从文件、流、写出器或系统ID (通常是相对或绝对URL) 中构建流结果。

3.7.5 使用StAX 写出XML 文档

javax.xml.stream.XMLOutputFactory 6

static XMLOutputFactory newInstance()
// 返回XMLOutputFactory 类的一个实例。
XMLStreamWriter createXMLStreamWriter(OutputStream in)
XMLStreamWriter createXMLStreamWriter(OutputStream in, String characterEncoding)
XMLStreamWriter createXMLStreamWriter(Writer in)
XMLStreamWriter createXMLStreamWriter(Result in)
// 创建写出到给定流、写出器或JAXP 结果的写出器。

javax. xml.stream.XMLStreamWriter 6

void writeStartDocument()
void writeStartDocument(String xmlVersion)
void writeStartDocument(String encoding, String xmlVersion)
// 在文档的顶部写入XML 处理指令。注意, encoding 参数只是用于写入这个属性,它不会设置输出的字符编码机制。
void setDefaultNamespace(String namespaceURI)
void setPrefix(String prefix, String namespaceURI)
// 设置默认的命名空间,或者具有前缀的命名空间。这种声明的作用域只是当前元素,如果没有写明具体元素,其作用域为文档的根。
void writeStartElement(String localName)
void writeStartElement(String namespaceURI, String localName)
// 写出一个开始标签, 其中namespaceURI 将用相关联的前缀来代替。
void writeEndElement()
// 关闭当前元素。
void writeEndDocument()
// 关闭所有打开的元素。
void writeEmptyElement(String localName)
void writeEmptyElement( String namespaceURI, String local Name)
// 写出一个自闭合的标签,其中namespaceURI 将用相关联的前缀来代替。
void writeAttribute(String localName, String value)
void writeAttribute(String namespaceURI, String localName, String value)
// 写出一个用于当前元素的属性,其中namespaceURI 将用相关联的前缀来代替。
void writeCharacters(String text)
// 写出字符数据。
void writeCData(String text)
// 写出CDATA 块。
void writeDTD(String dtd)
// 写出dtd 字符串,该字串需要包含一个DOCTYPE 声明。
void writeComment(String comment)
// 写出一个注释。
void close()
// 关闭这个写出器。

3.8 XSL 转换

javax.xml.transform.TransformerFactory 1.4

Transformer newTransformer(Source styleSheet)
// 返回一个transformer 类的实例,用来从指定的源中读取样式表。

javax.xml.transform.stream.StreamSource 1.4

StreamSource(File f)
StreamSource(InputStream in)
StreamSource(Reader in)
StreamSource(String systemID)
// 自一个文件、流、阅读器或系统ID (通常是相对或绝对URL) 构建一个数据流源。

javax.xml.transform.sax.SAXSource 1.4

SAX Source(XMLReader reader, InputSource source)
// 构建一个SAX 数据源,以便从给定输入源中获取数据,并使用给定的阅读器来解析输入数据。

org.xml.sax.XMLReader 1.4

void setContentHandler(ContentHandler handler)
// 设置在输入被解析时会被告知解析事件的处理器。
void parse(InputSource source)
// 解析来自给定输入源的输入数据,并将解析事件发送到内容处理器。

javax.xml.transform.dom.DOMResult 1.4

DOMResult(Node n)
// 自给定节点构建一个数据源。通常, n 是一个新文档节点。

org.xml.sax.helpers.Attributeslmpl 1.4

void addAttribute(String uri , String lname, String qname, String type, String value)
// 将一个属性添加到该属性集合。
// 参数: uri 名字空间的URI
//		 lname 无前缀的本地名
//		 qname 带前缀的限定名
//		 type 类型,“CDATA"、“ID"、“IDREF"、“IDREFS"、“NMTOKEN"、“NMTOKENS”、“ENTITY”、 “ENTITIES" 或“NOTATION" 之一
//		 value 属性值
void clear()
// 删除属性集合中的所有属性。
0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区