a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 724|回复: 0

[专业语言] Java认证辅导之关于Java语言的XPathAPI(5)

[复制链接]
发表于 2012-8-4 12:44:44 | 显示全部楼层 |阅读模式
Java认证辅导之关于Java语言的XPathAPI(5)
" j9 I& h/ _6 t% ~& j名称空间上下文
% I- ^9 S& o/ f0 N若 XML 文档中的元素在名称空间中,查询该文档的 XPath 表达式必须使用相同的名称空间。XPath 表达式不一定要使用相同的前缀,只需要名称空间 URI 相同即可。事实上,如果 XML 文档使用默认名称空间,那么尽管目标文档没有使用前缀,XPath 表达式也必须使用前缀。
( Z1 _4 w7 L0 `% Y6 M" f但是,Java 程序不是 XML 文档,因此不能用一般的名称空间解析。必须提供一个对象将前缀映射到名称空间 URI。该对象是javax.xml.namespace.NamespaceContext 接口的实例。比如,假设图书文档放在 http://www.example.com/books 名称空间中,如 清单 5 所示:  ]. G* Q" f: P" ^9 v  s
清单 5. 使用默认名称空间的 XML 文档
4 H- a$ T* p1 Y/ ]3 S6 O$ k5 M0 I: A7 i
              Snow Crash         Neal Stephenson         Spectra         0553380958         14.95            查找 Neal Stephenson 全部著作标题的 XPath 表达式就要改为 //pre:book[pre:author="Neal Stephenson"]/pre:title/text()。但是,必须将前缀 pre 映射到 URI http://www.example.com/books。NamespaceContext 接口在 Java 软件开发工具箱(JDK)或 JAXP 中没有默认实现似乎有点笨,但确实如此。不过,自己实现也不难。清单 6 对一个名称空间给出了简单的实现。还需要映射xml 前缀。
6 [2 m6 Q4 q/ g# d) g( N" B+ a' V清单 6. 绑定一个名称空间和默认名称空间的简单上下文
$ ~1 b' U7 C: {  {1 \* W& timport 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();     } } 用映射存储绑定和增加 setter 方法实现名称空间上下文的重用也不难。创建 NamespaceContext 对象后,在编译表达式之前将其安装到 XPath 对象上。以后就可以像以前一样是用这些前缀查询了。比如:" x) |* _5 j* c6 N, B, }
清单 7. 使用名称空间的 XPath 查询/ h5 J! R' \  G7 g

: I$ g) t# s* G' f4 x4 g6 CXPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); xpath.setNamespaceContext(new PersonalNamespaceContext()); XPathExpression expr   = xpath.compile("//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()); } 函数求解器
2 r% b* U" b! q% p2 @" r3 Y9 s有时候,在 Java 语言中定义用于 XPath 表达式的扩展函数很有用。这些函数可以执行用纯 XPath 很难或者无法执行的任务。不过必须是真正的函数,而不是随意的方法。就是说不能有副作用。(XPath 函数可以按照任意的顺序求值任意多次。)
! `1 g8 X0 e7 c; N. M, L通过 Java XPath API 访问的扩展函数必须实现 javax.xml.xpath.XPathFunction 接口。这个接口只声明了一个方法 evaluate:# X4 r1 V4 ^! \& s& d# F
, f' f& w5 m# R' b, o1 Y) Z( y
public Object evaluate(List args) throws XPathFunctionException 该方法必须返回 Java 语言能够转换到 XPath 的五种类型之一:
$ i1 L9 Z& z% S) q" v◆ String
3 z: {9 O; I( p◆ Double: N) m) v: M' {0 R
◆ Boolean2 f; `4 k4 m: a1 Z2 x" C
◆ Nodelist2 I% U0 l1 ?/ V- x: X, a( b( J
◆ Node" e6 k7 j" F2 |7 z
比如,清单 8 显示了一个扩展函数,它检查 ISBN 的校验和并返回 Boolean。这个校验和的基本规则是前九位数的每一位乘上它的位置(即第一位数乘上 1,第二位数乘上 2,依次类推)。将这些数加起来然后取除以 11 的余数。如果余数是 10,那么最后一位数就是 X。
* B, L0 |# p- f/ I) M, A清单 8. 检查 ISBN 的 XPath 扩展函数- e- V# Z/ R6 Q" ^
5 r  `$ ~. G* }* ~: A% B- H
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-'0');     }     int checkdigit = checksum % 11;     if (checkdigit + '0' == data[9] || (data[9] == 'X' && checkdigit == 10)) {         return Boolean.TRUE;     }     return Boolean.FALSE;   } } 下一步让这个扩展函数能够在 Java 程序中使用。为此,需要在编译表达式之前向 XPath 对象安装javax.xml.xpath.XPathFunctionResolver。函数求解器将函数的 XPath 名称和名称空间 URI 映射到实现该函数的 Java 类。清单 9是一个简单的函数求解器,将扩展函数 valid-isbn 和名称空间 http://www.example.org/books 映射到 清单 8 中的类。比如,XPath 表达式 //book[not(pre:valid-isbn(isbn))] 可以找到 ISBN 校验和不匹配的所有图书。& X" e4 V% g! F  s
清单 9. 识别 valid-isbn 扩展函数的上下文$ _8 q$ j0 m/ s9 x* T" I

! d! Z4 |3 V2 O) U: w9 Dimport 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,即便查询的文档没有使用任何名称空间。由于 XPathFunctionResolver、XPathFunction 和 NamespaceResolver 都是接口,如果方便的话可以将它们放在所有的类中。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-9-27 19:49 , Processed in 0.243137 second(s), 22 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表