2010-07-09 108 views
0

我想使用XPath从XML中过滤信息。XPath:如何正确实现XpathResolver

XPathFactory factory = XPathFactory.newInstance(); 
    XPath xpath = factory.newXPath(); 
    Object result = null; 
    // set the custom resolver to compares dates 
    xpath.setXPathFunctionResolver(new DateValidatorContext(PubUtils.getInstance().parseDate(date), operator)); 
    try {  
     PubUtils.getInstance().printDOM(feed, System.out); 
     XPathExpression expr = xpath.compile("//entry/content/artifact/resourceUri/text()"); 
    result = expr.evaluate(feed, XPathConstants.NODESET); 
    } catch (XPathExpressionException e) { 
    PublishService.logger.debug(e.getMessage()); 
    return null; 
    } 
    NodeList nodes = (NodeList) result; 
    for (int i = 0; i < nodes.getLength(); i++) { 
     System.out.println(nodes.item(i).getNodeValue()); 
    } 

我实现,检查如果日期是XPathResolver比给定的日期(等号/大/ LOWER)。

import java.util.Date; 
import java.util.List; 

import javax.xml.namespace.QName; 
import javax.xml.xpath.XPathFunction; 
import javax.xml.xpath.XPathFunctionException; 
import javax.xml.xpath.XPathFunctionResolver; 

import org.w3c.dom.Node; 
import org.w3c.dom.NodeList; 

import ....Operator; 

/** 
* XPathFunctionResolver to compare dates 
* 
*/ 
public class DateValidatorContext implements XPathFunctionResolver { 

private static final QName name = new QName(null, "compare-date"); 
private Date referenceDate = null; 
Operator operator = Operator.EQUALS; 

/** 
    * Sets the variables for comparison. Default comparison is equals 
    * 
    * @param referenceDate 
    *   date to compare to 
    */ 
public DateValidatorContext (Date referenceDate){ 
    this.referenceDate = referenceDate; 
} 

/** 
    * Sets the variables for comparison 
    * 
    * @param referenceDate 
    *   date to compare to 
    * @param operator 
    *   type of operation to execute (EQUALS, GREATER, LOWER) 
    */ 
public DateValidatorContext (Date referenceDate, Operator operator){ 
    this.referenceDate = referenceDate; 
    this.operator = operator; 
} 

public XPathFunction resolveFunction(QName name, int arity) { 
    if (name.equals(DateValidatorContext.name) && arity == 1) { 
    return new DateValidator(referenceDate, operator); 
    } 
    return null; 
} 

/** 
    * XPathFunction to compare dates 
    * 
    */ 
public class DateValidator implements XPathFunction{ 

    private Date referenceDate = null; 
    Operator operator = Operator.EQUALS; 

    /** 
    * Set the values for comparison 
    * 
    * @param referenceDate 
    *   date to compare to 
    * @param operator 
    *   type of operation to execute (EQUALS, GREATER, LOWER) 
    */ 
    public DateValidator (Date referenceDate, Operator operator){ 
    this.referenceDate = referenceDate; 
    this.operator = operator; 
    } 

    public Object evaluate(List args) throws XPathFunctionException { 
    if(args.size()!= 1){ 
    throw new XPathFunctionException("Wrong number of arguments to compare-date()"); 
    } 

    Date feedItemDate; 
     Object o = args.get(0); 

     // perform conversions 
     if (o instanceof String) feedItemDate = PubUtils.getInstance().parseDate((String) args.get(0)); 
     else if (o instanceof Boolean) feedItemDate = null; 
     else if (o instanceof Double) feedItemDate = null; 
     else if (o instanceof NodeList) { 
      NodeList list = (NodeList) o; 
      Node node = list.item(0); 
      feedItemDate= PubUtils.getInstance().parseDate(node.getTextContent()); 
     } 
     else { 
      throw new XPathFunctionException("Could not convert argument type"); 
     } 

     if(referenceDate != null && feedItemDate != null){ 
     int dateCompare = feedItemDate.compareTo(referenceDate); 
     switch(operator){ 
     case EQUALS: 
     if(dateCompare == 0){ 
      return Boolean.TRUE; 
     }   
     break; 
     case GREATER: 
     if(dateCompare > 0){ 
      return Boolean.TRUE; 
     }   
     break; 
     case LOWER: 
     if(dateCompare < 0){ 
      return Boolean.TRUE; 
     }   
     break; 
     default: 
     break; 
     } 
     } 

    return Boolean.FALSE; 
    } 
} 
} 

的问题是,在当前的表达

"//entry/content/artifact/resourceUri/text()" 

我越来越从XML的所有内容。 我该如何解决这个问题,以便只从XML获取我需要的信息?

示例XML:

<?xml version="1.0" encoding="UTF-8"?> 
<recentArtifactsFeed> 
<entry> 
    <updated>2010-07-08T00:54:22.859Z</updated> 
    <content lang="english" type="application/xml"> 
    <artifact><resourceUri>../types/_WDKRIYorEd-hG9AeAoU8_g</resourceUri></artifact> 
    </content> 
</entry> 
</recentArtifactsFeed> 

回答

0

我只是测试你的xpathExpression( “//进入/内容/神器/ resourceUri /文()”),没有XPathFunctionResolver,这给预期的结果。

我不能与XPathFunctionResolver测试,因为代码是不完整的(运营商,PubUtils,...),但我检查的Javadoc:

尤其解析器是 只要求功能 另一个名称空间(带有 显式前缀的函数)。这意味着你 不能使用 XPathFunctionResolver到 实施规范,比如XML签名 语法和处理这 在同一个命名空间扩展的XPath 1.0的函数库。这是 解析器设计的结果。

下面还给出了一个良好的开端:http://xml.apache.org/xalan-j/xpath_apis.html#functionresolver

总之,它需要三个步骤来使用functionresolvers:

  1. 创建XPathFunction
  2. 创建XPathFunctionResolver
  3. 创建NamespaceContext
+0

它只适用于命名空间......太糟糕了,我不得不手动执行来验证日期。 感谢您的回应:) – Gary 2010-07-09 21:49:06