XSD中的多属性打包

Posted on

XSD中的多属性打包

定义XSD的时候,除了元素外还有属性;在使用XML时属性也占有相当大的比例,由此可见属性十分重要。例如,定义一本图书的XML元素有图书名称、出版社、作者、价格等。以作者为例,可以将其联系方式作为一种属性,如qq、msn、tel,如图1.18所示。 说明: http://images.51cto.com/files/uploadimg/20110728/103912698.jpg(http://images.51cto.com/files/uploadimg/20110728/103912698.jpg) 图1.18 XSD中的多属性打包

使用xs:attributegGroup定义一个属性组,设置name="att"(为组命名),然后在xs:attributeGroup内部定义属性组的成员,成员数量没有限制。代码如下:

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

  2. <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"

  3. targetNamespace=http://www.mingrisoft.com xmlns="http://www.mingrisoft.com"

  4. elementFormDefault="qualified">

  5. <xs:element name="book">

  6. <xs:element name="name" type="xs:string" />

  7. <xs:element name="publisher" type="xs:string" />

  8. <xs:element name="company" type="xs:string" />

  9. <xs:element name="author">

  10. <xs:extension base="xs:string">

  11. <xs:attributeGroup ref="att">

  12. <xs:element name="ISBN" type="xs:string" />

  13. <xs:element name="price" type="xs:double" />

  14. <xs:element name="url" type="xs:string" />

  15. <xs:attributeGroup name="att">

  16. <xs:attribute name="tel" type="xs:string" use="required">

  17. <xs:attribute name="qq" type=" xs:integer">

  18. <xs:attribute name="msn" type=" xs:string">

(1)建立XSD文档,声明文档根元素和命名空间。声明一个根节点book,添加复杂类型xs:cimplexType以及book下的子元素(name、publisher、company、ISBN、price和url),为各个子元素添加xs:string类型限定。

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

  2. <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"

  3. targetNamespace=http://www.mingrisoft.com xmlns="http://www.mingrisoft.com"

  4. elementFormDefault="qualified">

  5. <xs:element name="book">

  6. <xs:element name="name" type="xs:string" />

  7. <xs:element name="publisher" type="xs:string" />

  8. <xs:element name="company" type="xs:string" />

  9. <xs:element name="ISBN" type="xs:string" />

  10. <xs:element name="price" type="xs:double" />

  11. <xs:element name="url" type="xs:string" />

(2)在company下面添加一个元素author,然后在xs:simpleType上扩展xs:simpleType和xs:extension元素,在xs:extension上为author内容声明属性xs:string。

  1. <xs:element name="author">

(3)在xs:schema内部和book根节点平级的地方,声明一个xs:attributeGroup,设置其name="att";在xs:attributeGroup内部声明3个属性,分别为tel、qq和msn,形成一个具有3个属性的属性组。

  1. <xs:attributeGroup name="att">

  2. <xs:attribute name="tel" type="xs:string" use="required">

  3. <xs:attribute name="qq" type="xs:integer">

  4. <xs:attribute name="msn" type="xs:string">

(4)在声明author 的地方,扩展xs:extension元素,在其内部声明一个xs:attributeGroup引用,引用刚才声明的属性组。

  1. <xs:extension base="xs:string">

  2. <xs:attributeGroup ref="att">

心法领悟018:author属性组中的属性。

在本实例中为author添加了一个属性组,内部有3个属性tel、qq、msn,这样是为了更好地说明xs:attributeGroup的使用方式,但一般不建议这么定义XML,最好的方式是把tel、qq和msn定义成author的子元素。

用XPath解析XML文档(二)

Posted on

用XPath解析XML文档(二)

用**JDOM XPath**类解析 JDOM API类支持XPath表达式从XML文档定位节点。JDOM XPath类的一些方法列在下表: XPath Class Method Description selectSingleNode 用于匹配XPath来定位单结点。 selectNodes 用于匹配XPath来定位结点集。 addNamespace 通过增加命名空间来匹配含有命名空间前缀的XPath。

在本节中,用JDOM XPath类从XML示例文档catalog.xml定位节点的过程将会被讨论。被select方法定位的结点被修改,被修改的文档输出成XML文档。首先,导入JDOM**的包org.jdom.xpath

import org.jdom.xpath./*;

创建一个SAXBuilder SAXBuilder saxBuilder =

new SAXBuilder("org.apache.xerces.parsers.SAXParser");

用SAXBuilder解析XML文档catalog.xml**: org.jdom.Document jdomDocument =

saxBuilder.build(xmlDocument);

xmlDocument是XML文档catalog.xml**的java.io.File代表,静态方法selectSingleNode(java.lang.Object context, String XPathExpression)用一个特定的XPath表达式定位一个单结点。如果超过一个结点匹配XPath表达式,则第一个结点被选择。用XPath定位一个journal的article元素属性结点level,并将journal属性结点title设置为Java Technology,将article元素属性结点date设置成January-2004。 org.jdom.Attribute levelNode =

(org.jdom.Attribute)(XPath.selectSingleNode(
    jdomDocument,

    "/catalog//journal[@title='JavaTechnology']" +
    "//article[@date='January-2004']/@level"));

则level属性值Advanced被定位,修改level结点。

levelNode.setValue("Intermediate");

selectSingleNode方法也可以用来在XML文档中定位结点。作为示例,选择一个title结点,用XPath定位结点。 org.jdom.Element titleNode =

(org.jdom.Element) XPath.selectSingleNode( jdomDocument,
"/catalog//journal//article[@date='January-2004']/title");

title结点值Design service-oriented architecture frameworks with J2EE technology被定位,修改title结点。 titleNode.setText(

"Service Oriented Architecture Frameworks");

静态方法selectNodes(java.lang.Object context, String XPathExpression)选择XPath指定的所有结点。定位journal的所有article结点,并将journal的属性title设置为Java Technology。 java.util.List nodeList =

XPath.selectNodes(jdomDocument,
"/catalog//journal[@title='Java Technology']//article");

修改article结点,添加属性到article结点。

Iterator iter=nodeList.iterator(); while(iter.hasNext()) {

org.jdom.Element element =
    (org.jdom.Element) iter.next();

element.setAttribute("section", "Java Technology");

}

JDOM XPath类支持定位含有命名空间前缀的结点。定位有命名空间的结点,添加命名空间到XPath:

XPath xpath = XPath.newInstance(

"/catalog//journal:journal//article/@journal:level");

xpath.addNamespace("journal",

"http://www.w3.org/2001/XMLSchema-Instance"

);

如上,则前缀为journal的命名空间添加到XPath对象。定位包含命名空间前缀的结点。

levelNode = (org.jdom.Attribute) xpath.selectSingleNode(jdomDocument);

属性结点journal:level被定位。修改此结点:

levelNode.setValue("Advanced");

Java程序JDomParser.java被用来从XML文档catalog.xml选择结点。在本节,介绍了用JDOMXPath类的select方法从一个XML**文档中定位结点的过程。定位的结点被修改,被修改的文档通过XMLOutputter类输出为一个XML文档。catalog-modified.xml就是此输出的XML**文档。 结论

在本教程中,用XPath解析了一个XML文档。XPath仅用来定位结点。在本教程中讨论的XPath API不是用来用XPathXML文档修改结点值的。为了修改结点的值,org.w3c.dom包的setter方法是必须的。

发表于 @ 2008年01月22日 11:47:00

使用jdom的XPath来快速定位xml节点

Posted on

使用jdom的XPath来快速定位xml节点

引入 jaxen包,使用SAX解析时,可用
XPath xpath = XPath.newInstance(“/root/node1/node1child[1]”);
来获取第一个节点node1child。

PS. XPath是一门用于在XML查找信息的语言,可以通过元素和属性进行导航。
XPath是W3C标准的主要元素,并且XQuery和Xpointer都是构建于XPath之上的,因此,对XPath的理解是很多高级XML应用的基础。

JDOM

Posted on

JDOM/XPATH编程指南

薛谷雨 , 高级JAVA工程师, NORDSAN信息科技开发有限公司

2004 年 5 月 01 日 本文分别介绍了 JDOM 和 XPATH,以及结合两者进行 XML 编程带来的好处。

前言

XML是一种优秀的数据打包和数据交换的形式,在当今XML大行于天下,如果没有听说过它的大名,那可真是孤陋寡闻了。用XML描述数据的优势显而易见,它具有结构简单,便于人和机器阅读的双重功效,并弥补了关系型数据对客观世界中真实数据描述能力的不足。W3C组织根据技术领域的需要,制定出了XML的格式规范,并相应的建立了描述模型,简称DOM。各种流行的程序设计语言都纷纷根据这一模型推出了自己的XML解析器,在JAVA世界里,APACHE组织开发的XERCES应该是流行最广功能最为强大的XML解析器之一。但是由于W3C在设计DOM模型时,并不是针对某一种语言而设计,因此为了通用性,加入了许多繁琐而不必要的细节 ,使JAVA程序员在开发XML的应用程序过程中感到不甚方便,因此JDOM作为一种新型的XML解析器横空出世,它不遵循DOM模型,建立了自己独立的一套JDOM模型(注意JDOM决不是DOM扩展,虽然名字差不多,但两者是平行的关系),并提供功能强大使用方便的类库,使JAVA程序员可以更为高效的开发自己的XML应用程序,并极大的减少了代码量,因此它很快得到了业内的认可,如JBUILDER这样的航空母舰级的重磅产品都以JDOM为XML解析引擎,足见其名不虚传。

有了XML数据的描述标准,人们自然就会想到应该有一种查询语言可以在XML中查找任意节点的数据,就像SQL语句可以在关系性数据库中执行查询操作一样,于是XQUERY和XPATH顺应潮流,应运而生。由于XQUERY较为复杂,使用不甚方便,XPATH渐渐成为主流,我们只需对XPATH进行学习,便可以应付所有的查询要求。在JDOM发布的最新的V1.0bata10版中,已经加入了对XPATH的支持,这无疑是令开发者十分激动的。

学会JDOM和XPATH,你便不再是XML的入门者,在未来的开发生涯中,就像特种兵的多用匕首,为你披荆斩棘,助你勇往直前。闲言少叙,学习还要脚踏实地,从头开始。

XPATH速成篇

XPATH遵循文档对象模型(DOM)的路径格式,由于每个XML文档都可以看成是一棵拥有许多结点的树,每个结点可以是以下七个类型之一:根(root)、元素(element)、属性(attribute)、正文(text)、命名空间(namespace)、处理指令(processing instruction)和注释(comment)。XPATH的基本语法由表达式构成。在计算表达式的值之后产生一个对象,这种对象有以下四种基本类型:节点集合、布尔型、数字型和字符串型 。XPATH基本上和在文件系统中寻找文件类似,如果路径是以"/"开头的,就表明该路径表示的是一个绝对路径,这和在UNIX系统中关于文件路径的定义是一致的。以"//"开头则表示在文档中的任意位置查找。

不谈泛泛的理论,学习XPATH还要从实例学起最为快捷,并有助于你举一反三。

下面的样例XML文档,描述了某台电脑中硬盘的基本信息(根节点代表硬盘,标签代表硬盘分区,从它的name属性可以看出有两个盘符名称为"C"和"D"的分区;每个分区下都包含,三个节点,分别代表了分区的空间大小、目录数量、所含文件个数): <?xml version="1.0" encoding="UTF-8"?> 8G 200 1580 10G 500 3000

你在XML文档中使用位置路径表达式来查找信息,这些表达式有很多种组成方式。

结点元素的查找是你将要碰到的最频繁的查找方式。在上面这个XML文档例子中,根HD包含disk结点。你可以使用路径来查找这些结点,用正斜杠(/)来分隔子结点,返回所有与模式相匹配的元素。下面的XPATH 语句返回所有的disk元素:

/HD/disk

"/"代表"全部"的意思。/HD// 代表HD下的全部节点。

下面的XPATH将返回任意节点下的名称为disk的全部节点:

//disk

下面的XPATH将返回名称为disk,name属性为'C'的全部节点:

/HD/disk[@name='C']

节点的附加元素,比如属性,函数等都要用方括号扩起来,属性前面要加上@号

下面的XPATH将返回文件个数为1580的files节点:

/HD/disk/files[text()='1580']

大家注意到上面包含一个text(),这就是XPATH的一个函数,它的功能是取出当前节点的文本。

下面的XPATH将返回文件个数为1580的分区:

/HD/disk/files[text()='1580']/parent::/*

最后的parent::/*表示这个元素的所有的父节点的集合。

XPATH中一些有用的函数: string concat (string, string, string/) 联接两个字符串 boolean starts-with (string, string) 判断某字符串是否以另一字符串开头 boolean contains (string, string) 判断某字符串是否包含另一字符串 string substring (string, number, number) 取子字符串 number string-length (string) 测字符串长度 number sum (node-set) 求和 number floor (number) 求小于此数的最大整数值 number *ceiling (number) 求大于此数最小整数值

XPATH具有丰富的表达功能,上面这些已经基本够用,在你做项目中就会发现根据实际情况有许多查询需求,你应该参考本文最后提供的W3C发布的关于XAPH的官方资料进行查阅,我在这里只起一个抛砖引玉的作用,在下面的章节中,我们的应用范例将不会超出上面提到的这些内容,如果你对XPATH感兴趣,应该在读完本文后,查找相关资料和书籍进行深入学习。

JDOM修炼篇

用过XERCES的程序员都会感到,有时候用一句话就可以说清楚的事,当用XERCES的API来实现时,要三四行程序。

获得并安装JDOM

http://www.jdom.org/可以下载JDOM的最新版本,将压缩包中的jdom.jar及lib目录下的全部jar包加入到classpath就可以了。

用JDOM解析XML

JDOM模型的全部类都在org.jdom./这个包里,org.jdom.input./这个包里包含了JDOM的解析器,其中的DOMBuilder的功能是将DOM模型的Document解析成JDOM模型的Document;SAXBuilder的功能是从文件或流中解析出符合JDOM模型的XML树。由于我们的上面提到的XML样例存储在一个名称为sample.xml的文件中,很显然我们应该采用后者作为解析工具。下面程序演示了jdom的基本功能,即解析一个xml文档,并挑选一些内容输出到屏幕上。 import java.util./; import org.jdom./; import org.jdom.input.SAXBuilder; public class Sample1 { public static void main(String[] args) throws Exception{ SAXBuilder sb=new SAXBuilder(); Document doc=sb.build("sample.xml"); Element root=doc.getRootElement(); List list=root.getChildren("disk"); for(int i=0;i<list.size();i++){ Element element=(Element)list.get(i); String name=element.getAttributeValue("name"); String capacity=element.getChildText("capacity"); String directories=element.getChildText("directories"); String files=element.getChildText("files"); System.out.println("磁盘信息:"); System.out.println("分区盘符:"+name); System.out.println("分区容量:"+capacity); System.out.println("目录数:"+directories); System.out.println("文件数:"+files); System.out.println("-----------------------------------"); } } }

程序的输出结果: 磁盘信息: 分区盘符:C 分区容量:8G 目录数:200 文件数:1580 ----------------------------------- 磁盘信息: 分区盘符:D 分区容量:10G 目录数:500 文件数:3000 -----------------------------------

这段程序采用了传统的解析方式,一级一级的从根节点到子节点逐个采集我们所需要的数据,中规中矩。试想如果这个树足够深,我们想取第5 0层第三个节点的数据(夸张了点,呵呵),那将是一场噩梦!下面的内容将轻松化解你的这一痛苦。

JDOM+XPATH进阶篇

说了那么多JDOM和XPATH的好处,终于到了英雄有用武之地的时候了。

JDOM的关于XPATH的api在org.jdom.xpath这个包里。看看这个包下,只有一个类,JDOM就是如此简洁,什么事都不故弄玄虚的搞得那么复杂。这个类中的核心的api主要是两个selectNodes()和selectSingleNode()。前者根据一个xpath语句返回一组节点;后者根据一个xpath语句返回符合条件的第一个节点。

下面的程序我们用JDOM+XPATH实现了上一个程序同样的功能,你可以从中学到不少运用XPATH 的知识: import java.util./; import org.jdom./; import org.jdom.input.SAXBuilder; import org.jdom.xpath.XPath; public class Sample2 { public static void main(String[] args) throws Exception { SAXBuilder sb = new SAXBuilder(); Document doc = sb.build("sample.xml"); Element root = doc.getRootElement(); List list = XPath.selectNodes(root, "/HD/disk"); for (int i = 0; i > list.size(); i++) { Element disk_element = (Element) list.get(i); String name = disk_element.getAttributeValue("name"); String capacity = ( (Text) XPath.selectSingleNode(disk_element, "//disk[@name='" + name + "']/capacity/text()")).getTextNormalize(); String directories = ( (Text) XPath.selectSingleNode(disk_element, "//disk[@name='" + name + "']/directories/text()")).getTextNormalize(); String files = ( (Text) XPath.selectSingleNode(disk_element, "//disk[@name='" + name + "']/files/text()")).getTextNormalize(); System.out.println("磁盘信息:"); System.out.println("分区盘符:" + name); System.out.println("分区容量:" + capacity); System.out.println("目录数:" + directories); System.out.println("文件数:" + files); System.out.println("-----------------------------------"); } } }

输出结果: 磁盘信息: 分区盘符:C 分区容量:8G 目录数:200 文件数:1580 ----------------------------------- 磁盘信息: 分区盘符:D 分区容量:10G 目录数:500 文件数:3000 -----------------------------------

结语

技术在日新月异的发展。永远没有学过后,便可以一劳永逸的技术。XML的发展一日千里。W3C作为INTERNET方面的权威组织指导着互联网技术的发展方向。新技术的出现大都围绕着W3C制订的标准,但往往有些“旁门左道”的另类功法却能产生惊人的杀伤力。JDOM就是这众多旁门中的一朵奇葩。就像J2EE大行其道的今天,有许多开源组织仍旧在默默的打造着自己的独家兵器,谁又能说在不久的将来,他们不会成为划时代的创造呢? 君不见Hibernate的兴起正在有力的震撼着J2EE中EJB架构的基石。只要是成型的框架,必然有薄弱的软肋。新的技术只要能攻入对方这一弱点,便可在业界站一席之地。本文只起抛砖引玉的作用,相信读者在吃过这道快餐之后,一定会发现窗外有更美丽的风景等待我们去游历。

参考资料

jdom解析xml

Posted on

jdom解析xml

jdom解析xml xml是一种广为使用的可扩展标记语言,java中解析xml的方式有很多,最常用的像jdom、dom4j、sax等等。前两天刚好有个程序需要解析xml,就学了下jdom,写了个小例子,这里做个学习笔记。

要使用jdom解析xml文件,需要下载jdom的包,我使用的是jdom-1.1。解压之后,将lib文件夹下的.jar文件以及build文件夹下的jdom.jar拷贝到工程文件夹下,然后就可以使用jdom操作xml文件了。

一、读取xml文件

假设有这样一个xml文件:

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

oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:@localhost:1521:database why why 哈尔滨 嫩江

首先,用 org.jdom.input.SAXBuilder 这个类取得要操作的xml文件,会返回一个 org.jdom.Document 对象,这里需要做一下异常处理。然后,取得这个xml文件的根节点,org.jdom.Element 代表xml文件中的一个节点,取得跟节点后,便可以读取xml文件中的信息。利用 org.jdom.xpath.XPath 可以取得xml中的任意制定的节点中的信息。
例如,要取得上面文件中的 <jdbc-info> 下的 <driver-class-name> 中的内容,先取得这个节点Element driverClassNameElement = (Element)XPath.selectSingleNode(rootEle, "//sys-config/jdbc-info/driver-class-name"),注意,根节点前要使用两个 "/" ,然后,用 driverClassNameElement.getText() 便可以取得这个节点下的信息。
如果一个节点下有多个名称相同的子节点,可以用XPath.selectNodes()方法取得多个子节点的List,遍历这个List就可以操作各个子节点的内容了。
下面是我写的读取上面xml文件的例子,比起文字描述更直观一些吧:

package com.why.jdom;

import java.io.IOException; import java.util.Iterator; import java.util.List;

import org.jdom.input.SAXBuilder; import org.jdom.xpath.XPath; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException;

public class ReadXML {

/**
 * @param args
 */
public static void main(String[] args) {
    SAXBuilder sax = new SAXBuilder();
    try {
        Document doc = sax.build("src/config.xml");
        Element rootEle = doc.getRootElement();
        Element driverClassNameElement = (Element)XPath.selectSingleNode(rootEle, "//sys-config/jdbc-info/driver-class-name");
        String driverClassName = driverClassNameElement.getText();
        System.out.println("driverClassName = " + driverClassName);
        List provinceList = XPath.selectNodes(rootEle, "//sys-config/provinces-info/province");
        for(Iterator it = provinceList.iterator();it.hasNext();){
            Element provinceEle = (Element)it.next();
            String proId = provinceEle.getAttributeValue("id");
            String proName = provinceEle.getAttributeValue("name");

            System.out.println("provinceId = " + proId + "   provinceName = " + proName);
            List cityEleList = (List)provinceEle.getChildren("city");
            for(Iterator cityIt = cityEleList.iterator();cityIt.hasNext();){
                Element cityEle = (Element)cityIt.next();
                String cityId = cityEle.getAttributeValue("id");
                String cityName = cityEle.getText();

                System.out.println("    cityId = " + cityId + "   cityName = " + cityName);
            }
        }
    } catch (JDOMException e) {
        // TODO 自动生成 catch 块
        e.printStackTrace();
    } catch (IOException e) {
        // TODO 自动生成 catch 块
        e.printStackTrace();
    }

}

}

二、写xml文件

写xml文件与读取xml文件的操作类似,利用 org.jdom.output.XMLOutputter 就可以将处理好的xml输出到文件了。可以设置文件的编码方式,不过一般使用UTF-8就可以了。代码如下:

package com.why.jdom;

import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;

import org.jdom.Document; import org.jdom.Element; import org.jdom.output.XMLOutputter;

public class WriteXML {

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO 自动生成方法存根
    Element rootEle = new Element("sys-config");
    Element provincesEle = new Element("provinces-info");
    Element provinceEle = new Element("province");
    provinceEle.setAttribute("id","hlj");
    provinceEle.setAttribute("name","黑龙江省");
    Element cityEle1 = new Element("city");
    cityEle1.setAttribute("id","harb");
    cityEle1.addContent("哈尔滨");
    Element cityEle2 = new Element("city");
    cityEle2.setAttribute("id","nj");
    cityEle2.addContent("嫩江");
    provinceEle.addContent(cityEle1);
    provinceEle.addContent(cityEle2);
    provincesEle.addContent(provinceEle);
    rootEle.addContent(provincesEle);
    Document doc = new Document(rootEle);
    XMLOutputter out = new XMLOutputter();

// out.setFormat(Format.getCompactFormat().setEncoding("GBK"));//设置文件编码,默认为UTF-8 String xmlStr = out.outputString(doc); System.out.println(xmlStr); try { out.output(doc, new FileOutputStream("c:/test.xml")); } catch (FileNotFoundException e) { // TODO 自动生成 catch 块 e.printStackTrace(); } catch (IOException e) { // TODO 自动生成 catch 块 e.printStackTrace(); } }

}