a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 669|回复: 0

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

[复制链接]
发表于 2012-8-4 12:44:44 | 显示全部楼层 |阅读模式
Java认证辅导之关于Java语言的XPathAPI(5)9 L6 P7 ~. t6 j. x! O' s  a
名称空间上下文3 B; t' E. z7 R3 m! c$ X& z) W9 z; \
若 XML 文档中的元素在名称空间中,查询该文档的 XPath 表达式必须使用相同的名称空间。XPath 表达式不一定要使用相同的前缀,只需要名称空间 URI 相同即可。事实上,如果 XML 文档使用默认名称空间,那么尽管目标文档没有使用前缀,XPath 表达式也必须使用前缀。
4 E( k# k8 b3 S& k: w但是,Java 程序不是 XML 文档,因此不能用一般的名称空间解析。必须提供一个对象将前缀映射到名称空间 URI。该对象是javax.xml.namespace.NamespaceContext 接口的实例。比如,假设图书文档放在 http://www.example.com/books 名称空间中,如 清单 5 所示:/ t) J1 P2 b9 d7 y8 `
清单 5. 使用默认名称空间的 XML 文档3 A: @. Z! M; y/ k# j7 o$ N

3 j  I- B0 c, V1 m6 r& {# F0 P4 o              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 前缀。
8 i/ ^9 k& G' n2 R清单 6. 绑定一个名称空间和默认名称空间的简单上下文; \+ t/ X. O" |
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();     } } 用映射存储绑定和增加 setter 方法实现名称空间上下文的重用也不难。创建 NamespaceContext 对象后,在编译表达式之前将其安装到 XPath 对象上。以后就可以像以前一样是用这些前缀查询了。比如:
: T" G8 o* e( Q6 _: f/ U清单 7. 使用名称空间的 XPath 查询
9 i; W. u' ~$ h+ c; w" x7 v; w. _4 S
XPathFactory 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()); } 函数求解器! r" y$ a0 X* m1 S" f% l
有时候,在 Java 语言中定义用于 XPath 表达式的扩展函数很有用。这些函数可以执行用纯 XPath 很难或者无法执行的任务。不过必须是真正的函数,而不是随意的方法。就是说不能有副作用。(XPath 函数可以按照任意的顺序求值任意多次。)
% s3 K7 J8 Q' _7 P; N7 |通过 Java XPath API 访问的扩展函数必须实现 javax.xml.xpath.XPathFunction 接口。这个接口只声明了一个方法 evaluate:% u" A2 g, b- k5 |" L

# T0 B! w# X9 E4 h2 S: Cpublic Object evaluate(List args) throws XPathFunctionException 该方法必须返回 Java 语言能够转换到 XPath 的五种类型之一:
* S$ T, j8 S8 Q# |* N5 \◆ String
; g7 x4 _- M2 l2 f6 ~* o1 Q) t3 u& f◆ Double
: g. b- c! F+ R! [: m& [9 B6 [◆ Boolean. h0 }6 L* P8 T9 b
◆ Nodelist" Y5 @8 G. |- Z! R; Z0 F* b
◆ Node
3 t6 w9 o; h) h/ g/ O; B比如,清单 8 显示了一个扩展函数,它检查 ISBN 的校验和并返回 Boolean。这个校验和的基本规则是前九位数的每一位乘上它的位置(即第一位数乘上 1,第二位数乘上 2,依次类推)。将这些数加起来然后取除以 11 的余数。如果余数是 10,那么最后一位数就是 X。! D: {7 V: J! G$ _- m) V
清单 8. 检查 ISBN 的 XPath 扩展函数1 n$ k: ?  g( _; u  {
' p6 Y  G, Y, |, q6 P8 Y8 c' ~
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 校验和不匹配的所有图书。% M4 [' ^9 G' U) r$ c' l
清单 9. 识别 valid-isbn 扩展函数的上下文3 s2 j6 e' \) S% B# P' K6 W: K
3 q7 h  ^; _& |  ~: G/ w% A
import 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-4-26 20:05 , Processed in 0.173514 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

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