XPath:如何正确实现XpathResolver

时间:2010-07-09 01:17:34

标签: java xml xpath

我想使用XPath来过滤XML中的信息。

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,它检查日期是否(EQUALS / GREATER / 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>

1 个答案:

答案 0 :(得分:1)

我刚测试了你的xpathExpression(“// entry / content / artifact / resourceUri / text()”),没有XPathFunctionResolver,这就得到了预期的结果。

我无法使用XPathFunctionResolver进行测试,因为代码不完整(Operator,PubUtils,...),但我检查了javadoc:

  

特别是解析器是   只调用一个函数   另一个命名空间(带有一个   显式前缀)。这意味着你   不能用了   XPathFunctionResolver来   实现XML-Signature等规范   语法和处理   扩展XPath的函数库   1.0在同一名称空间中。这是设计的结果   解析器。

以下也是一个良好的开端:http://xml.apache.org/xalan-j/xpath_apis.html#functionresolver

简而言之,使用functionresolvers需要三个步骤:

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