« | August 2025 | » | 日 | 一 | 二 | 三 | 四 | 五 | 六 | | | | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | | | | | | | |
| 公告 |
戒除浮躁,读好书,交益友 |
Blog信息 |
blog名称:邢红瑞的blog 日志总数:523 评论数量:1142 留言数量:0 访问次数:9692122 建立时间:2004年12月20日 |

| |
[java语言]使用saxon的xpath的问题  原创空间, 软件技术, 电脑与网络
邢红瑞 发表于 2007/12/9 18:25:13 |
很久不写blog了,最近用xpath,发现xpath 1.0不够用了,想起来xquery也许不错,发现支持xquery的java库只有saxon。大多数xpath的支持库jdom dom4j jaxp还有jaxen仅支持xpath 1.0,xpath2.0久不支持,还好xpath 2.0是xquery的子集,可以使用saxon了。第一次运行saxon的例子就出现了问题,这是saxon提供的使用sun的jaxp的xpath的例子,其中没有用到saxon。import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.xml.sax.InputSource;
import javax.xml.namespace.QName;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.xpath.*;import java.io.BufferedReader;import java.io.File;import java.io.InputStreamReader;
/** * Class XPathExampleDOM: * * This is a variant of the XPathExample application written to use DOM interfaces. Using the DOM * rather than Saxon's native tree model is not recommended unless the application has other reasons * to use the DOM model, but this application shows how it can be done when necessary. * * This class illustrates the use of the JAXP XPath API. It is a simple command-line application, * which prompts the user for a word, and replies with a list of all the lines containing that * word within a Shakespeare play. * * * @author Michael H. Kay (Michael.H.Kay@ntlworld.com) * @version Auguest 2005: modified to use DOM interfaces */
public class XPathExampleDOM implements XPathVariableResolver {
private String currentWord;
/** * main()<BR> * Expects one argument, the input filename<BR> */
public static void main (String args[]) throws Exception { // Check the command-line arguments
if (args.length != 1) { System.err.println("Usage: java XPathExampleDOM input-file"); System.exit(1); } XPathExampleDOM app = new XPathExampleDOM(); app.go(args[0]); }
/** * Run the application */
public void go(String filename) throws Exception {
XPathFactory xpf = XPathFactory.newInstance(XPathConstants.DOM_OBJECT_MODEL); XPath xpe = xpf.newXPath(); System.err.println("Loaded XPath Provider " + xpe.getClass().getName());
// Build the source document. DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); System.err.println("Using DocumentBuilderFactory " + dfactory.getClass());
dfactory.setNamespaceAware(true);
DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); System.err.println("Using DocumentBuilder " + docBuilder.getClass());
Node doc = docBuilder.parse(new InputSource(new File(filename).toURL().toString()));
// Declare a variable resolver to return the value of variables used in XPath expressions xpe.setXPathVariableResolver(this);
// Compile the XPath expressions used by the application
XPathExpression findLine = xpe.compile("//LINE[contains(., $word)]"); XPathExpression findLocation = xpe.compile("concat(ancestor::ACT/TITLE, ' ', ancestor::SCENE/TITLE)"); XPathExpression findSpeaker = xpe.compile("string(ancestor::SPEECH/SPEAKER[1])");
// Create a reader for reading input from the console
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
// Loop until the user enters "." to end the application
while (true) {
// Prompt for input System.out.println("\n>>>> Enter a word to search for, or '.' to quit:\n");
// Read the input String word = in.readLine().trim(); if (word.equals(".")) { break; } if (!word.equals("")) {
// Set the value of the XPath variable currentWord = word;
// Find the lines containing the requested word NodeList matchedLines = (NodeList)findLine.evaluate(doc, XPathConstants.NODESET);
// Process these lines boolean found = false; final int len = matchedLines.getLength(); for (int i=0; i<len; i++) {
// Note that we have found at least one line found = true;
// Get the next matching line Node line = matchedLines.item(i);
// Find where it appears in the play System.out.println('\n' + findLocation.evaluate(line));
// Output the name of the speaker and the content of the line System.out.println(findSpeaker.evaluate(line) + ": " + line.getTextContent()); }
// If no lines were found, say so if (!found) { System.err.println("No lines were found containing the word '" + word + '\''); } } }
// Finish when the user enters "." System.out.println("Finished."); }
/** * This class serves as a variable resolver. The only variable used is $word. * @param qName the name of the variable required * @return the current value of the variable */
public Object resolveVariable(QName qName) { if (qName.getLocalPart().equals("word")) { return currentWord; } else { return null; } }
}我也是第一次发现xpath中居然可以定义变量,看了看sun的文档还可以定义函数呢。这段代码在没有saxon的saxon9-xpath.jar,运行ok,如果有saxon9-xpath.jar,抛出Exception in thread "main" javax.xml.xpath.XPathExpressionException: Cannot locate an object model implementation for nodes of class com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl高人maomaode说是classpath有问题,我比较了一次两次的日志Loaded XPath Provider com.sun.org.apache.xpath.internal.jaxp.XPathImplUsing DocumentBuilderFactory class com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImplUsing DocumentBuilder class com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImplLoaded XPath Provider net.sf.saxon.xpath.XPathEvaluatorUsing DocumentBuilderFactory class com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImplUsing DocumentBuilder class com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImplxpath的提供者不同,导致出了问题,看了看sun的javadocJAXP提供的接口可以自定义Xpath的实现,抽象类XPathFactory 有两个静态newInstance()方法初始化一个具体的工厂用来封装实现. newInstance() 可以使用system property 来决定使用那一个实现.Xalan-Java 2的预配置META-INF/services/javax.xml.xpath.XPathFactory,里面的值为org.apache.xpath.jaxp.XPathFactoryImpl.也可以动态设置,sun的javadoc说明public static final XPathFactory newInstance(String uri) throws XPathFactoryConfigurationException获取使用指定对象模型的新 XPathFactory 实例。为了查找 XPathFactory 对象,此方法按以下顺序查找以下位置,其中“类加载器”指上下文类加载器:如果存在系统属性 DEFAULT_PROPERTY_NAME + ":uri"(其中 uri 是此方法的参数),则其值作为类名称读取。该方法将试图通过使用类加载器创建此类的新实例,如果创建成功,则返回它。 读取 ${java.home}/lib/jaxp.properties,并查找与作为系统属性的键关联的值。如果存在,则按上面的方式处理该值。 类加载器要求服务提供者的提供者配置文件与资源目录 META-INF/services 中的 javax.xml.xpath.XPathFactory 匹配。有关文件格式和解析规则,请参阅 JAR File Specification。每个可能的服务提供者均要实现该方法: isObjectModelSupported(String objectModel)返回支持指定对象模型的类加载器顺序中的第一个服务提供者。 以特定于平台的方式来定位平台默认的 XPathFactory。必须存在 W3C DOM 的平台默认 的 XPathFactory,即 DEFAULT_OBJECT_MODEL_URI。 如果这些都失败,则抛出 XPathFactoryConfigurationException。疑难解答提示:有关如何精确解析属性文件的信息,请参阅 Properties.load(java.io.InputStream)。尤其是,冒号 ':'在属性文件中需要转义,因此要确保 URI 在其中进行正确转义。例如:
http\://java.sun.com/jaxp/xpath/dom=org.acme.DomXPathFactory 参数:uri - 标识底层对象模型。规范只定义了 URI DEFAULT_OBJECT_MODEL_URI、用于 W3C DOM 的 http://java.sun.com/jaxp/xpath/dom、org.w3c.dom 包。至于其他对象模型,实现可随意引入其他 URI。 返回:XPathFactory 的实例。 抛出: XPathFactoryConfigurationException - 如果指定的对象模型不可用。 NullPointerException - 如果 uri 为 null。 IllegalArgumentException - 如果 uri 为 null 或 uri.length() == 0。但是设置System.setProperty("javax.xml.xpath.XPathFactory:"+NamespaceConstant.OBJECT_MODEL_SAXON, "com.sun.org.apache.xpath.internal.jaxp.XPathImpl"); XPathFactory xpf = XPathFactory.newInstance(XPathConstants.DOM_OBJECT_MODEL); System.out.println(XPathConstants.DOM_OBJECT_MODEL);没有任何作用,没有办法,只有使用软件的爆破了,打开saxon9-xpath.jar,将里面的META-INF\services下javax.xml.xpath.XPathFactory改为net.sf.saxon.xpath.XPathFactoryImplhttp\://java.sun.com/jaxp/xpath/dom: com.sun.org.apache.xpath.internal.jaxp.XPathImplhttp\://saxon.sf.net/jaxp/xpath/om: net.sf.saxon.xpath.XPathFactoryImplhttp\://www.xom.nu/jaxp/xpath/xom: net.sf.saxon.xpath.XPathFactoryImplhttp\://jdom.org/jaxp/xpath/jdom: net.sf.saxon.xpath.XPathFactoryImplhttp\://www.dom4j.org/jaxp/xpath/dom4j: net.sf.saxon.xpath.XPathFactoryImpl原因是这样的.即时你定义了http://java.sun.com/jaxp/xpath/dom,但是http://java.sun.com/jaxp/xpath/dom被改为net.sf.saxon.xpath.XPathFactoryImpl,不出问题就怪了.打包运行,一切ok. |
|
|