??xml version="1.0" encoding="utf-8" standalone="yes"?> 1. 介绍 1QDOM(JAXP Crimson解析? 2QSAX SAX处理的优炚w常类g媒体的优点。分析能够立卛_始,而不是等待所有的数据被处理。而且Q由于应用程序只是在d数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优炏V事实上Q应用程序甚至不必解析整个文档;它可以在某个条g得到满时停止解析。一般来_SAXq比它的替代者DOM快许多? 3QJDOM http://www.jdom.org/ JDOM的目的是成ؓJava特定文档模型Q它化与XML的交互ƈ且比使用DOM实现更快。由于是W一个Java特定模型QJDOM一直得到大力推q和促进。正在考虑通过“Java规范hJSR-102”它最l用?#8220;Java标准扩展”。从2000q初已l开始了JDOM开发? JDOM与DOM主要有两斚w不同。首先,JDOM仅用具体类而不使用接口。这在某些方面简化了APIQ但是也限制了灵zL。第二,API大量使用了Collectionsc,化了那些已经熟悉q些cȝJava开发者的使用? JDOM文档声明其目的是“使用20%(或更?的精力解?0%(或更?Java/XML问题”(Ҏ学习曲线假定?0%)。JDOM对于大多数Java/XML应用E序来说当然是有用的Qƈ且大多数开发者发现API比DOMҎ理解得多。JDOMq包括对E序行ؓ的相当广泛检查以防止用户做Q何在XML中无意义的事。然而,它仍需要您充分理解XML以便做一些超出基本的工作(或者甚至理解某些情况下的错?。这也许是比学习DOM或JDOM接口都更有意义的工作? JDOM自n不包含解析器。它通常使用SAX2解析器来解析和验证输入XML文档(管它还可以以前构造的DOM表示作ؓ输入)。它包含一些{换器以将JDOM表示输出成SAX2事g、DOM模型或XML文本文档。JDOM是在Apache许可证变体下发布的开放源码?/p>
4QDOM4J http://dom4j.sourceforge.net/ 为支持所有这些功能,DOM4J使用接口和抽象基本类Ҏ。DOM4J大量使用了API中的Collectionsc,但是在许多情况下Q它q提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是Q虽然DOM4J付出了更复杂的API的代P但是它提供了比JDOM大得多的灉|性? 在添加灵zL、XPath集成和对大文档处理的目标ӞDOM4J的目标与JDOM是一LQ针对Java开发者的易用性和直观操作。它q致力于成ؓ比JDOM更完整的解决ҎQ实现在本质上处理所有Java/XML问题的目标。在完成该目标时Q它比JDOM更少防止不正的应用E序行ؓ? DOM4J是一个非帔R怼U的Java XML APIQ具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的Y件。如今你可以看到来多的Java软g都在使用DOM4J来读写XMLQ特别值得一提的是连Sun的JAXM也在用DOM4J? 2.. 比较 1QDOM4J性能最好,qSun的JAXM也在用DOM4J。目前许多开源项目中大量采用DOM4JQ例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文g。如果不考虑可移植性,那就采用DOM4J. 2QJDOM和DOM在性能试时表C佻I在测?0M文档时内存溢出。在文档情况下q值得考虑使用DOM和JDOM。虽然JDOM的开发者已l说明他们期望在正式发行版前专注性能问题Q但是从性能观点来看Q它实没有值得推荐之处。另外,DOM仍是一个非常好的选择。DOM实现q泛应用于多U编E语a。它q是许多其它与XML相关的标准的基础Q因为它正式获得W3C推荐(与基于非标准的Java模型相对)Q所以在某些cd的项目中可能也需要它(如在JavaScript中用DOM)?/p>
3QSAX表现较好Q这要依赖于它特定的解析方式Q事仉动。一个SAX即到来的XML,但ƈ没有载入到内?当然当XML被dӞ会有部分文档暂时隐藏在内存中)?/p>
3. 四种xml操作方式的基本用方?/p>
xml文gQ?/p>
<?xml version="1.0" encoding="utf-8" ?> 1QDOM import Java.io.*; public class MyXMLReader{ long lasting =System.currentTimeMillis(); 2QSAX import org.xml.sax.*; public class MyXMLReader extends DefaultHandler { Java.util.Stack tags = new Java.util.Stack(); public static void main(String args[]) { System.out.println("q行旉Q? + (System.currentTimeMillis() - lasting) + "毫秒");} public void startElement(String uri,String localName,String qName,Attributes attrs) { 3Q?JDOM import Java.io.*; public class MyXMLReader { public static void main(String arge[]) { } 4QDOM4J import Java.io.*; public class MyXMLReader { public static void main(String arge[]) { 如果要告诉别Z一加仑牛奶Q您会怎么_“请去C加仑牛奶回来” q是 “从前门出去,向左转,C个街区向双{Q再走半个街区向双{q入商店。走向四号通道Q沿通道Cc_左,拿一瓶一加仑装的牛奶然后到收银台付款。再沿原路回家?#8221; 直太可笑了。只要在 “请去C加仑牛奶回来” 的基上稍加指C,多数成h都能自己买回牛奶来? 查询语言和计机搜烦与此cM。直接说 “找一?Cryptonomicon 的副?#8221; 要比~写搜烦某个数据库的详细逻辑Ҏ得多。由于搜索操作的逻辑非常怼Q可以发明一U通用语言让您使用 “扑ֈ Neal Stephenson 的所有著?#8221; q样的命令,然后~写对特定数据存储执行此cL询的引擎? 在众多查询语a之中Q结构化查询语言QSQLQ是一U针Ҏ询特定类型的关系库而设计和优化的语a。其他不那么常见的查询语aq有对象查询语言QOQLQ和 XQuery。但本文的主题是 XPathQ一Uؓ查询 XML 文档而设计的查询语言。比如,下面q个单的 XPath 查询可以在文档中扑ֈ作者ؓ Neal Stephenson 的所有图书的标题Q?/p>
作ؓ对照Q查询同样信息的U?DOM 搜烦代码?清单 1 所C: 不论您是否相信,清单 1 中的 DOM 昄不如单的 XPath 表达式通用或者健壮。您愿意~写、调试和l护哪一个?我想{案很明显? 但是虽然有很强的表达能力QXPath q不?Java 语言Q事实上 XPath 不是一U完整的~程语言。有很多东西?XPath 表达不出来,甚至有些查询也无法表达。比方说QXPath 不能查找国际标准图书~码QISBNQ检验码不匹配的所有图书,或者找出境外帐h据库昄Ơ帐的所有作者。幸q的是,可以?XPath l合?Java E序中,q样p发挥两者的优势了:Java ?Java 所擅长的,XPath ?XPath 所擅长的? 直到最q,Java E序执行 XPath 查询所需要的应用E序~程接口QAPIQ还因Ş形色色的 XPath 引擎而各不相同。Xalan 有一U?APIQSaxon 使用另一U,其他引擎则用其他的 API。这意味着代码往往把您限制CU品上。理x况下Q最好能够试验具有不同性能特点的各U引擎,而不会带来不适当的麻烦或者重新编写代码? 于是QJava 5 推出? 我将举例说明如何使用它。然后再讨论一些细节问题。假设要查询一个图书列表,L Neal Stephenson 的著作。具体来_q个图书列表的Ş式如 清单 2 所C:
查找所有图书的 XPath 查询非常单: 现在我提供一个简单的E序Q它?Java 语言中执行这个查询,然后把找到的所有图书的标题打印出来。首先,需要将文档加蝲C?DOM 到目前ؓ止,q仅仅是标准?JAXP ?DOMQ没有什么新鲜的? 接下来创? 然后使用q个工厂创徏
如果 XPath 表达式只使用一ơ,可以跌~译步骤直接? 最后,计算 XPath 表达式得到结果。表辑ּ是针对特定的上下文节点计的Q在q个例子中是整个文档。还必须指定q回cd。这里要求返回一个节炚wQ? 可以结果强制{化成 DOM
清单 4
把上q片D늻合到了一个程序中。还要注意,q些Ҏ可能抛出一些检查异常,q些异常必须? 每当混合使用诸如 XPath ?Java q样两种不同的语aӞ必定会有某些两者粘合在一L明显接缝。ƈ非一切都很合拍。XPath ?Java 语言没有同样的类型系l。XPath 1.0 只有四种基本数据cdQ?/p>
当然QJava 语言有更多的数据cdQ包括用户定义的对象cd?/p>
多数 XPath 表达式,特别是位|\径,都返回节炚w。但是还有其他可能。比如,XPath 表达?
前面一直假设您使用的是 XPath 1.0。XPath 2 大大扩展和修改了cdpȝ。Java XPath API 支持 XPath 2 所需的主要修Ҏ?XPath 2 新数据类型增加常量? ?Java 中计?XPath 表达式时Q第二个参数指定需要的q回cd。有五种可能Q都? 最后一? 如果不能完成要求的{换, ?XML 文档中的元素在名U空间中Q查询该文档?XPath 表达式必M用相同的名称I间。XPath 表达式不一定要使用相同的前~Q只需要名U空?URI 相同卛_。事实上Q如?XML 文档使用默认名称I间Q那么尽目标文档没有用前~QXPath 表达式也必须使用前缀? 但是QJava E序不是 XML 文档Q因此不能用一般的名称I间解析。必L供一个对象将前缀映射到名U空?URI。该对象? 查找 Neal Stephenson 全部著作标题?XPath 表达式就要改? 使用映射存储l定和增?setter Ҏ实现名称I间上下文的重用也不难? 创徏 有时候,?Java 语言中定义用?XPath 表达式的扩展函数很有用。这些函数可以执行用U?XPath 很难或者无法执行的d。不q必L真正的函敎ͼ而不是随意的Ҏ。就是说不能有副作用。(XPath 函数可以按照L的顺序求gQ意多ơ。) 通过 Java XPath API 讉K的扩展函数必d? 该方法必返?Java 语言能够转换?XPath 的五U类型之一Q? 比如Q?a >清单 8 昄了一个扩展函敎ͼ它检?ISBN 的校验和q返? 下一步让q个扩展函数能够?Java E序中用。ؓ此,需要在~译表达式之前向 XPath 对象安装 ׃扩展函数必须有名U空_所以计包含扩展函数的表达式时必须使用 ?SQL ?XPath q样的声明性语a~写查询Q要比?Java ?C q样的命令式语言Ҏ得多。但是,?Java ?C q样的图灵完整语a~写复杂的逻辑Q又?SQL ?XPath q样的声明性语aҎ得多。所q的是,通过使用 Java Database Connectivity (JDBC) ?
DOM是用与^台和语言无关的方式表CXML文档的官方W3C标准。DOM是以层次l构l织的节Ҏ信息片断的集合。这个层ơ结构允许开发h员在树中L特定信息。分析该l构通常需要加载整个文档和构造层ơ结构,然后才能做Q何工作。由于它是基于信息层ơ的Q因而DOM被认为是Z树或Z对象的。DOM以及q义的基于树的处理具有几个优炏V首先,׃树在内存中是持久的,因此可以修改它以便应用程序能Ҏ据和l构作出更改。它q可以在M时候在树中上下DQ而不是像SAX那样是一ơ性的处理。DOM使用h也要单得多?/p>
选择DOMq是选择SAXQ?对于需要自q写代码来处理XML文档的开发h员来_ 选择DOMq是SAX解析模型是一个非帔R要的设计决策?DOM采用建立树Şl构的方式访问XML文档Q而SAX采用的事件模型?
DOM解析器把XML文档转化Z个包含其内容的树Qƈ可以Ҏq行遍历。用DOM解析模型的优Ҏ~程ҎQ开发h员只需要调用徏树的指oQ然后利用navigation APIs讉K所需的树节点来完成Q务。可以很Ҏ的添加和修改树中的元素。然而由于用DOM解析器的时候需要处理整个XML文档Q所以对性能和内存的要求比较高,其是遇到很大的XML文g的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频J的改变的服务中?
SAX解析器采用了Z事g的模型,它在解析XML文档的时候可以触发一pd的事Ӟ当发现给定的tag的时候,它可以激zM个回调方法,告诉该方法制定的标签已经扑ֈ。SAX对内存的要求通常会比较低Q因为它让开发h员自己来军_所要处理的tag。特别是当开发h员只需要处理文档中所包含的部分数据时QSAXq种扩展能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难Q而且很难同时讉K同一个文档中的多处不同数据?
虽然DOM4J代表了完全独立的开发结果,但最初,它是JDOM的一U智能分支。它合ƈ了许多超出基本XML文档表示的功能,包括集成的XPath支持、XML Schema支持以及用于大文档或化文档的基于事件的处理。它q提供了构徏文档表示的选项Q它通过DOM4J API和标准DOM接口hq行讉K功能。从2000下半q开始,它就一直处于开发之中?
<Result>
<VALUE>
<NO DATE="2005">A1</NO>
<ADDR>GZ</ADDR>
</VALUE>
<VALUE>
<NO DATE="2004">A2</NO>
<ADDR>XG</ADDR>
</VALUE>
</Result>
import Java.util.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;
public static void main(String arge[]){
try{
File f=new File("data_10k.xml");
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc = builder.parse(f);
NodeList nl = doc.getElementsByTagName("VALUE");
for (int i=0;iQnl.getLength();i++){
System.out.print("车牌L:" + doc.getElementsByTagName("NO").item(i).getFirstChild().getNodeValue());
System.out.println("车主地址:" + doc.getElementsByTagName("ADDR").item(i).getFirstChild().getNodeValue());
}
}catch(Exception e){
e.printStackTrace();
}
import org.xml.sax.helpers.*;
import javax.xml.parsers.*;
public MyXMLReader() {
super();
}
long lasting = System.currentTimeMillis();
try {
SAXParserFactory sf = SAXParserFactory.newInstance();
SAXParser sp = sf.newSAXParser();
MyXMLReader reader = new MyXMLReader();
sp.parse(new InputSource("data_10k.xml"), reader);
} catch (Exception e) {
e.printStackTrace();
}
public void characters(char ch[], int start, int length) throws SAXException {
String tag = (String) tags.peek();
if (tag.equals("NO")) {
System.out.print("车牌LQ? + new String(ch, start, length));
}
if (tag.equals("ADDR")) {
System.out.println("地址:" + new String(ch, start, length));
}
}
tags.push(qName);}
}
import Java.util.*;
import org.jdom.*;
import org.jdom.input.*;
long lasting = System.currentTimeMillis();
try {
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(new File("data_10k.xml"));
Element foo = doc.getRootElement();
List allChildren = foo.getChildren();
for(int i=0;iQallChildren.size();i++) {
System.out.print("车牌L:" + ((Element)allChildren.get(i)).getChild("NO").getText());
System.out.println("车主地址:" + ((Element)allChildren.get(i)).getChild("ADDR").getText());
}
} catch (Exception e) {
e.printStackTrace();
}
import Java.util.*;
import org.dom4j.*;
import org.dom4j.io.*;
long lasting = System.currentTimeMillis();
try {
File f = new File("data_10k.xml");
SAXReader reader = new SAXReader();
Document doc = reader.read(f);
Element root = doc.getRootElement();
Element foo;
for (Iterator i = root.elementIterator("VALUE"); i.hasNext();) {
foo = (Element) i.next();
System.out.print("车牌L:" + foo.elementText("NO"));
System.out.println("车主地址:" + foo.elementText("ADDR"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
]]>
]]>
]]>
//book[author="Neal Stephenson"]/title
清单 1. 扑ֈ Neal Stephenson 所有著?title 元素?DOM 代码
ArrayList result = new ArrayList();
NodeList books = doc.getElementsByTagName("book");
for (int i = 0; i < books.getLength(); i++) {
Element book = (Element) books.item(i);
NodeList authors = book.getElementsByTagName("author");
boolean stephenson = false;
for (int j = 0; j < authors.getLength(); j++) {
Element author = (Element) authors.item(j);
NodeList children = author.getChildNodes();
StringBuffer sb = new StringBuffer();
for (int k = 0; k < children.getLength(); k++) {
Node child = children.item(k);
// really should to do this recursively
if (child.getNodeType() == Node.TEXT_NODE) {
sb.append(child.getNodeValue());
}
}
if (sb.toString().equals("Neal Stephenson")) {
stephenson = true;
break;
}
}
if (stephenson) {
NodeList titles = book.getElementsByTagName("title");
for (int j = 0; j < titles.getLength(); j++) {
result.add(titles.item(j));
}
}
}
javax.xml.xpath
包,提供一个引擎和对象模型独立?XPath 库。这个包也可用于 Java 1.3 及以后的版本Q但需要单独安?Java API for XML Processing (JAXP) 1.3。Xalan 2.7 ?Saxon 8 以及其他产品包含了这个库的实现?
回页?/font>
清单 2. 包含图书信息?XML 文档
<inventory>
<book year="2000">
<title>Snow Crash</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<isbn>0553380958</isbn>
<price>14.95</price>
</book>
<book year="2005">
<title>Burning Tower</title>
<author>Larry Niven</author>
<author>Jerry Pournelle</author>
<publisher>Pocket</publisher>
<isbn>0743416910</isbn>
<price>5.99</price>
<book>
<book year="1995">
<title>Zodiac</title>
<author>Neal Stephenson<author>
<publisher>Spectra</publisher>
<isbn>0553573862</isbn>
<price>7.50</price>
<book>
<!-- more books... -->
</inventory>
抽象工厂
XPathFactory
是一个抽象工厂。抽象工厂设计模式得这一U?API 能够支持不同的对象模型,?DOM、JDOM ?XOM。ؓ了选择不同的模型,需要向 XPathFactory.newInstance()
Ҏ传递标识对象模型的l一资源标识W(URIQ。比?http://xom.nu/ 可以选择 XOM。但实际上,到目前ؓ?DOM 是该 API 支持的惟一对象模型?//book[author="Neal Stephenson"]
。ؓ了找些图书的标题Q只要增加一步,表达式就变成?//book[author="Neal Stephenson"]/title
。最后,真正需要的?title
元素的文本节点孩子。这p求再增加一步,完整的表辑ּ是 //book[author="Neal Stephenson"]/title/text()
?Document
对象中。ؓ了简化v见,假设该文档在当前工作目录?books.xml 文g中。下面的单代码片D解析文档ƈ建立对应?Document
对象Q?
清单 3. ?JAXP 解析文档
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse("books.xml");
XPathFactory
Q?/p>
XPathFactory factory = XPathFactory.newInstance();
XPath
对象Q?
XPath xpath = factory.newXPath();
XPath
对象~译 XPath 表达式:
PathExpression expr = xpath.compile("http://book[author='Neal Stephenson']/title/text()");
直接求?/b>
XPath
对象调用 evaluate()
Ҏ。但是,如果同一个表辑ּ要重复用多ơ,~译可能更快一些?
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList
Q然后遍历列表得到所有的标题Q?
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
throws
子句中声明,但是我在上面把它们掩盖v来了Q?
清单 4. 用固定的 XPath 表达式查?XML 文档的完整程?/b>
import Java.io.IOException;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
public class XPathExample {
public static void main(String[] args)
throws ParserConfigurationException, SAXException,
IOException, XPathExpressionException {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("books.xml");
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr
= xpath.compile("http://book[author='Neal Stephenson']/title/text()");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
}
}
count(//book)
q回文档中的图书数量。XPath 表达?count(//book[@author="Neal Stephenson"]) > 10
q回一个布|如果文档?Neal Stephenson 的著作超q?10 本则q回 trueQ否则返?false?evaluate()
Ҏ被声明ؓq回 Object
。实际返回什么依赖于 XPath 表达式的l果以及要求的类型。一般来_XPath ?/p>
Java.lang.Double
Java.lang.String
Java.lang.Boolean
org.w3c.dom.NodeList
XPath 2
javax.xml.xpath.XPathConstants
cM命名了常量:
XPathConstants.NODESET
XPathConstants.BOOLEAN
XPathConstants.NUMBER
XPathConstants.STRING
XPathConstants.NODE
XPathConstants.NODE
实际上没有匹配的 XPath cd。只有知?XPath 表达式只q回一个节Ҏ者只需要一个节Ҏ才用它。如?XPath 表达式返回了多个节点q且指定?XPathConstants.NODE
Q则 evaluate()
按照文档序q回W一个节炏V如?XPath 表达式选择了一个空集ƈ指定?XPathConstants.NODE
Q则 evaluate()
q回 null?evaluate()
抛?XPathException
?
javax.xml.namespace.NamespaceContext
接口的实例。比如,假设图书文档攑֜ http://www.example.com/books 名称I间中,?清单 5 所C:
清单 5. 使用默认名称I间?XML 文档
<inventory xmlns="http://www.example.com/books">
<book year="2000">
<title>Snow Crash</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<isbn>0553380958</isbn>
<price>14.95<price>
</book>
<!-- more books... -->
<inventory>
//pre:book[pre:author="Neal Stephenson"]/pre:title/text()
。但是,必须前~ pre
映射?URI http://www.example.com/books?code>NamespaceContext 接口?Java 软g开发工LQJDKQ或 JAXP 中没有默认实C乎有点笨Q但实如此。不q,自己实现也不难?a >清单 6 对一个名U空间给Z单的实现。还需要映?xml
前缀?
清单 6. l定一个名U空间和默认名称I间的简单上下文
import Java.util.Iterator;
import javax.xml.*;
import javax.xml.namespace.NamespaceContext;
public class PersonalNamespaceContext implements NamespaceContext {
public String getNamespaceURI(String prefix) {
if (prefix == null) throw new NullPointerException("Null prefix");
else if ("pre".equals(prefix)) return "http://www.example.org/books";
else if ("xml".equals(prefix)) return XMLConstants.XML_NS_URI;
return XMLConstants.NULL_NS_URI;
}
// This method isn't necessary for XPath processing.
public String getPrefix(String uri) {
throw new UnsupportedOperationException();
}
// This method isn't necessary for XPath processing either.
public Iterator getPrefixes(String uri) {
throw new UnsupportedOperationException();
}
}
NamespaceContext
对象后,在编译表辑ּ之前其安装?XPath
对象上。以后就可以像以前一h用这些前~查询了。比如:
清单 7. 使用名称I间?XPath 查询
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new PersonalNamespaceContext());
XPathExpression expr
= xpath.compile("http://pre:book[pre:author='Neal Stephenson']/pre:title/text()");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
javax.xml.xpath.XPathFunction
接口。这个接口只声明了一个方?evaluateQ?
public Object evaluate(List args) throws XPathFunctionException
String
Double
Boolean
Nodelist
Node
Boolean
。这个校验和的基本规则是前九位数的每一位乘上它的位|(即第一位数乘上 1Q第二位C?2Q依ơ类推)。将q些数加h然后取除?11 的余数。如果余数是 10Q那么最后一位数是 X?
清单 8. ?ISBN ?XPath 扩展函数
import Java.util.List;
import javax.xml.xpath.*;
import org.w3c.dom.*;
public class ISBNValidator implements XPathFunction {
// This class could easily be implemented as a Singleton.
public Object evaluate(List args) throws XPathFunctionException {
if (args.size() != 1) {
throw new XPathFunctionException("Wrong number of arguments to valid-isbn()");
}
String isbn;
Object o = args.get(0);
// perform conversions
if (o instanceof String) isbn = (String) args.get(0);
else if (o instanceof Boolean) isbn = o.toString();
else if (o instanceof Double) isbn = o.toString();
else if (o instanceof NodeList) {
NodeList list = (NodeList) o;
Node node = list.item(0);
// getTextContent is available in Java 5 and DOM 3.
// In Java 1.4 and DOM 2, you'd need to recursively
// accumulate the content.
isbn= node.getTextContent();
}
else {
throw new XPathFunctionException("Could not convert argument type");
}
char[] data = isbn.toCharArray();
if (data.length != 10) return Boolean.FALSE;
int checksum = 0;
for (int i = 0; i < 9; i++) {
checksum += (i+1) * (data[i]-'0');
}
int checkdigit = checksum % 11;
if (checkdigit + '0' == data[9] || (data[9] == 'X' && checkdigit == 10)) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
}
javax.xml.xpath.XPathFunctionResolver
。函数求解器函数的 XPath 名称和名U空?URI 映射到实现该函数?Java cR?a >清单 9 是一个简单的函数求解器,扩展函?valid-isbn
和名U空?http://www.example.org/books 映射?清单 8 中的cR比如,XPath 表达?//book[not(pre:valid-isbn(isbn))]
可以扑ֈ ISBN 校验和不匚w的所有图书?
清单 9. 识别 valid-isbn 扩展函数的上下文
iimport javax.xml.namespace.QName;
import javax.xml.xpath.*;
public class ISBNFunctionContext implements XPathFunctionResolver {
private static final QName name
= new QName("http://www.example.org/books", "valid-isbn");
public XPathFunction resolveFunction(QName name, int arity) {
if (name.equals(ISBNFunctionContext.name) && arity == 1) {
return new ISBNValidator();
}
return null;
}
}
NamespaceResolver
Q即便查询的文档没有使用M名称I间。由?XPathFunctionResolver
?code>XPathFunction ?NamespaceResolver
都是接口Q如果方便的话可以将它们攑֜所有的cM?
javax.xml.xpath
之类?API 可以两者结合v来。随着世界上越来越多的数据转向 XMLQ?code>javax.xml.xpath 与 Java.sql
一样变得越来越重要?/p>
]]>
q是标准的XML文档的首行代码,因ؓXSLT本n也是XML文档?br />encoding属性用来定义文档用的~码形式Qiso-8859-1主要支持西欧和北的语言~码?br />如果你想使用体中文,那么应该写成:
<?xml version="1.0" encoding="GB2312"?>
接下ȝ代码?
<xsl:stylesheet xmlns:xsl="
q是标准的XSLT文g首行代码。xsl:stylesheet代码的意思是文档作Z个样式表?stylesheet)处理?br />xmlns:xsl属性是一个名字空间声明,和XML中的名字I间使用Ҏ一P用来防止元素名称重复和乱?br />其中前缀xsl的意思是文档中用的元素遵守W3C的XSLT规范?br />最后的version属性说明样式表只采用XSLT 1.0的标准功能,q也是目前仅有的标准?/p>
<xsl:template match="/"> 一?lt;xsl:template>元素定义一个模板规则。属性match="/"说明XML源文档中Q这个模板规则作用的L?/"是一UXPath语法Q我们在后面详l讲qͼq里?/"代表XMLl构树的?root)?/p>
接下ȝ代码? <html> <head> <title>First XSLT Example</title> </head> <body> <p><xsl:value-of select="greeting"/></p> </body> </html> 说明Q当模板规则被触发,模板的内容就会控制输出的l果。例子中Q模板大部分内容由HTML?br />素和文本构成。只?lt;xsl:value-of>元素是XSLT语法Q这?lt;xsl:value-of>的作用是拯原文档中?br />一个节点的值到输出文档。而select属性则详细指定要处理的节点名称。这是XPath语法Q?greeting" 提示Q由于XML文档是严格的层l构(用IE5查看XML文gQ会看见XML文档cM多兌菜单)Q?br />所以我们Ş象的UXML文档为文档树Q其中每一对元素称作树的一个节炏V根元素是根节炏V?/p>
最后关闭所有元素: </xsl:template> </xsl:stylesheet>
技?/span>
1
/XPath: string end-with
的意思就是寻找根节点名ؓgreeting的元素,q用模板来处理这个节炏V具体的是扑ֈ<greeting>
元素Q然后将元素的?hello world"按模板样式拷贝到输出文g?
]]>
XmlNode.InnerText
?/span>
.InnerXml
的区别是Q前者将内容中的
<
?/span>
>
分别变成
<
?/span>
>
Q因此,希望两D?/span>
XmlDocument
合ƈ的程序只能?/span>
XmlDocumentFragment.InnerXml = XmlNode.OuterXml
技?/span>
2
<xsl:for-each select="root/data[substring-after(@name,'.')= 'Text' and string-length(value)>0]">
技?/span>
3
一?/span>
XML
文档?/span>
Load
时如果失败,是Ҏ不合法;是否W合某个
Schema
Q?/span>
XSD
Q的要求则是有效?/span>
(valid)
查,Ҏ是?/span>
XmlValidatingReader
对象?/span>
Schemas
?/span>
ValidationType
属性?/span>
技?/span>
4
XmlDataDocument
cL?/span>
XmlDocument
z出来的,最重要的是增加了一?/span>
DataSet
属性。不q这个类不是
System.Xml
提供的,而是
System.Data
提供的。对于L要跟数据库打交道的应用程序来_反正是要引用
System.Data
的,不如全部?/span>
XmlDataDocument
?/span>
技?/span>
5
如何?/span>
XmlDataDocument
对象中的
DataSet
更新保存到数据库中?
DataSet
本n有一?/span>
AcceptChanges
ҎQ所以只需要:
xmlDataDoc.DataSet.AcceptChanges();
]]>