mybatis xpath实现

阅读更多

Java 5 推出了 javax.xml.xpath 包,这是一个用于 XPath 文档查询的独立于 XML 对象模型的库。

强大的xpath表达式支持对xml document文档检索信息。

 

 



    
        Snow Crash
        Neal Stephenson
        Spectra
        0553380958
        14.95
    
 
    
        Burning Tower
        Larry Niven
        Jerry Pournelle
        Pocket
        0743416910
        5.99
    
 
    
        Zodiac
        Neal Stephenson
        Spectra
        0553573862
        7.50
    

 

import java.io.IOException;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
public class XPathExample {
	 public static void main(String[] args) 
	   throws ParserConfigurationException, SAXException, 
	          IOException, XPathExpressionException {
		//创建 XPathFactory:
	    DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
	    domFactory.setNamespaceAware(true); // never forget this!
	    DocumentBuilder builder = domFactory.newDocumentBuilder();
	    Document doc = builder.parse("book.xml");
	    
	    XPathFactory factory = XPathFactory.newInstance();
	    //这个工厂创建 XPath 对象:
	    XPath xpath = factory.newXPath();
	    //设置命名空间
//	    xpath.setNamespaceContext(new PersonalNamespaceContext());
	    //XPath 对象编译 XPath 表达式:
	    XPathExpression expr  = xpath.compile("//book[author='Neal Stephenson']/title/text()");
	    //doc是整个节点
	    /**
	     * XPathConstants.NODESET
			XPathConstants.BOOLEAN
			XPathConstants.NUMBER
			XPathConstants.STRING
			XPathConstants.NODE
			定义了返回类型
			xpath 和java的映射关系
			number 映射为 java.lang.Double
			string 映射为 java.lang.String
			boolean 映射为 java.lang.Boolean
			node-set 映射为 org.w3c.dom.NodeList
	     */
	    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()); 
	    }
	  }
}

 

 

xpath 表达式代码

 

XPathExpression expr  = xpath.compile("//book[author='Neal Stephenson']/title/text()");

 //book[author='Neal Stephenson'book标签 下的text为Neal Stephenson的author标签

 

/title/test()是title 标签的文本

 

 

很简单吧,再说一下

 

实体解析器SAX EntityResolver

这里有它详细的解释:http://www.ibm.com/developerworks/cn/xml/tips/x-tipent/

让xml文档包含外部实体引用

 

package com.ibm.developerWorks;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class CopyrightResolver implements EntityResolver {
 public InputSource resolveEntity(String publicID, String systemID)
 throws SAXException {
 if (systemID.equals("http://www.ibm.com/developerworks/copyright.xml")) {
 // Return local copy of the copyright.xml file
 return new InputSource("/usr/local/content/localCopyright.xml");
 }
 // If no match, returning null makes process continue normally
 return null;
 }

 再你的xml解析类中每次解析都会调用这个方法,这样就避免了每次都要加载外部资源的消耗。

 

xpase的公用类:

 

 

import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.apache.ibatis.builder.BuilderException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class XPathParser {

  private Document document;//dom对象
  private boolean validation;//是否验证 domFactory.setNamespaceAware(validation);
  private EntityResolver entityResolver;//实体解析器
  private Properties variables;//配置文件
  private XPath xpath;//xpath

  public XPathParser(String xml) {
    commonConstructor(false, null, null);//初始化XPath对象
    this.document = createDocument(new InputSource(new StringReader(xml)));//获取dom对象
  }

  public XPathParser(Reader reader) {
    commonConstructor(false, null, null);
    this.document = createDocument(new InputSource(reader));
  }

  public XPathParser(InputStream inputStream) {
    commonConstructor(false, null, null);
    this.document = createDocument(new InputSource(inputStream));
  }

  public XPathParser(Document document) {
    commonConstructor(false, null, null);
    this.document = document;
  }

  public XPathParser(String xml, boolean validation) {
    commonConstructor(validation, null, null);
    this.document = createDocument(new InputSource(new StringReader(xml)));
  }

  public XPathParser(Reader reader, boolean validation) {
    commonConstructor(validation, null, null);
    this.document = createDocument(new InputSource(reader));
  }

  public XPathParser(InputStream inputStream, boolean validation) {
    commonConstructor(validation, null, null);
    this.document = createDocument(new InputSource(inputStream));
  }

  public XPathParser(Document document, boolean validation) {
    commonConstructor(validation, null, null);
    this.document = document;
  }

  public XPathParser(String xml, boolean validation, Properties variables) {
    commonConstructor(validation, variables, null);
    this.document = createDocument(new InputSource(new StringReader(xml)));
  }

  public XPathParser(Reader reader, boolean validation, Properties variables) {
    commonConstructor(validation, variables, null);
    this.document = createDocument(new InputSource(reader));
  }

  public XPathParser(InputStream inputStream, boolean validation, Properties variables) {
    commonConstructor(validation, variables, null);
    this.document = createDocument(new InputSource(inputStream));
  }

  public XPathParser(Document document, boolean validation, Properties variables) {
    commonConstructor(validation, variables, null);
    this.document = document;
  }

  public XPathParser(String xml, boolean validation, Properties variables, EntityResolver entityResolver) {
    commonConstructor(validation, variables, entityResolver);
    this.document = createDocument(new InputSource(new StringReader(xml)));
  }

  public XPathParser(Reader reader, boolean validation, Properties variables, EntityResolver entityResolver) {
    commonConstructor(validation, variables, entityResolver);
    this.document = createDocument(new InputSource(reader));
  }

  public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
    commonConstructor(validation, variables, entityResolver);
    this.document = createDocument(new InputSource(inputStream));
  }

  public XPathParser(Document document, boolean validation, Properties variables, EntityResolver entityResolver) {
    commonConstructor(validation, variables, entityResolver);
    this.document = document;
  }

  public void setVariables(Properties variables) {
    this.variables = variables;
  }

  public String evalString(String expression) {
    return evalString(document, expression);
  }

  public String evalString(Object root, String expression) {
    String result = (String) evaluate(expression, root, XPathConstants.STRING);
    result = PropertyParser.parse(result, variables);
    return result;
  }

  public Boolean evalBoolean(String expression) {
    return evalBoolean(document, expression);
  }

  public Boolean evalBoolean(Object root, String expression) {
    return (Boolean) evaluate(expression, root, XPathConstants.BOOLEAN);
  }

  public Short evalShort(String expression) {
    return evalShort(document, expression);
  }

  public Short evalShort(Object root, String expression) {
    return Short.valueOf(evalString(root, expression));
  }

  public Integer evalInteger(String expression) {
    return evalInteger(document, expression);
  }

  public Integer evalInteger(Object root, String expression) {
    return Integer.valueOf(evalString(root, expression));
  }

  public Long evalLong(String expression) {
    return evalLong(document, expression);
  }

  public Long evalLong(Object root, String expression) {
    return Long.valueOf(evalString(root, expression));
  }

  public Float evalFloat(String expression) {
    return evalFloat(document, expression);
  }

  public Float evalFloat(Object root, String expression) {
    return Float.valueOf(evalString(root, expression));
  }

  public Double evalDouble(String expression) {
    return evalDouble(document, expression);
  }

  public Double evalDouble(Object root, String expression) {
    return (Double) evaluate(expression, root, XPathConstants.NUMBER);
  }

  public List evalNodes(String expression) {
    return evalNodes(document, expression);
  }

  public List evalNodes(Object root, String expression) {
    List xnodes = new ArrayList();
    NodeList nodes = (NodeList) evaluate(expression, root, XPathConstants.NODESET);
    for (int i = 0; i < nodes.getLength(); i++) {
      xnodes.add(new XNode(this, nodes.item(i), variables));
    }
    return xnodes;
  }

  public XNode evalNode(String expression) {
    return evalNode(document, expression);
  }

  public XNode evalNode(Object root, String expression) {
    Node node = (Node) evaluate(expression, root, XPathConstants.NODE);
    if (node == null) {
      return null;
    }
    return new XNode(this, node, variables);
  }

  private Object evaluate(String expression, Object root, QName returnType) {
    try {
      return xpath.evaluate(expression, root, returnType);
    } catch (Exception e) {
      throw new BuilderException("Error evaluating XPath.  Cause: " + e, e);
    }
  }

  private Document createDocument(InputSource inputSource) {
    // important: this must only be called AFTER common constructor
    try {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      factory.setValidating(validation);

      factory.setNamespaceAware(false);
      factory.setIgnoringComments(true);
      factory.setIgnoringElementContentWhitespace(false);
      factory.setCoalescing(false);
      factory.setExpandEntityReferences(true);

      DocumentBuilder builder = factory.newDocumentBuilder();
      builder.setEntityResolver(entityResolver);//设置实体解析器
      builder.setErrorHandler(new ErrorHandler() {
        public void error(SAXParseException exception) throws SAXException {
          throw exception;
        }

        public void fatalError(SAXParseException exception) throws SAXException {
          throw exception;
        }

        public void warning(SAXParseException exception) throws SAXException {
        }
      });
      return builder.parse(inputSource);
    } catch (Exception e) {
      throw new BuilderException("Error creating document instance.  Cause: " + e, e);
    }
  }

  private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
    this.validation = validation;
    this.entityResolver = entityResolver;
    this.variables = variables;
    XPathFactory factory = XPathFactory.newInstance();
    this.xpath = factory.newXPath();
  }

}

 

 

 

这里用到了一个字符串解析器:

PropertyParser 它是来处理字符串中${}这样的字符,去配置文件中查找。

 

解析器模式:

 

 

 

import java.util.Properties;

public class PropertyParser {

  public static String parse(String string, Properties variables) {
    VariableTokenHandler handler = new VariableTokenHandler(variables);
    GenericTokenParser parser = new GenericTokenParser("${", "}", handler);
    return parser.parse(string);
  }

  private static class VariableTokenHandler implements TokenHandler {
    private Properties variables;

    public VariableTokenHandler(Properties variables) {
      this.variables = variables;
    }

    public String handleToken(String content) {
      if (variables != null && variables.containsKey(content)) {
        return variables.getProperty(content);
      }
      return "${" + content + "}";
    }
  }
}

 

 

GenericTokenParser.java

 

public class GenericTokenParser {

  private final String openToken;
  private final String closeToken;
  private final TokenHandler handler;

  public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
    this.openToken = openToken;
    this.closeToken = closeToken;
    this.handler = handler;
  }

  public String parse(String text) {
    StringBuilder builder = new StringBuilder();
    if (text != null && text.length() > 0) {//如果传入的字符串有值
      //将字符串转为字符数组
      char[] src = text.toCharArray();
      int offset = 0;
      //判断openToken在text中的位置,注意indexOf函数的返回值-1表示不存在,0表示在在开头的位置
      int start = text.indexOf(openToken, offset);
      while (start > -1) {
        if (start > 0 && src[start - 1] == '\\') {
          //如果text中在openToken前存在转义符就将转义符去掉。如果openToken前存在转义符,start的值必然大于0,最小也为1
          //因为此时openToken是不需要进行处理的,所以也不需要处理endToken。接着查找下一个openToken
          builder.append(src, offset, start - 1).append(openToken);
          offset = start + openToken.length();//重设offset
        } else {
          int end = text.indexOf(closeToken, start);
          if (end == -1) {//如果不存在openToken,则直接将offset位置后的字符添加到builder中
            builder.append(src, offset, src.length - offset);
            offset = src.length;//重设offset
          } else {
            builder.append(src, offset, start - offset);//添加openToken前offset后位置的字符到bulider中
            offset = start + openToken.length();//重设offset
            String content = new String(src, offset, end - offset);//获取openToken和endToken位置间的字符串
            builder.append(handler.handleToken(content));//调用handler进行处理
            offset = end + closeToken.length();//重设offset
          }
        }
        start = text.indexOf(openToken, offset);//开始下一个循环
      }
      //只有当text中不存在openToken且text.length大于0时才会执行下面的语句
      if (offset < src.length) {
        builder.append(src, offset, src.length - offset);
      }
    }
    return builder.toString();
  }

}

 简单的说,这个函数的作用就是将openToken和endToken间的字符串取出来用handler处理下,然后再拼接到一块。我们接下来看一个具体的handler,了解下它对传入的字符串做了怎样的处理。

 

 

在XMLConfigBuilder这个类中有它的调用实例:

 

 

 

  //很关键是xpath的表达式语言 匹配对象 放入configuration中 
  private void parseConfiguration(XNode root) {
    try {
      propertiesElement(root.evalNode("properties")); //issue #117 read properties first
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      settingsElement(root.evalNode("settings"));
      environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

 这里使用了解析器设计模式,这里的文件可以单独作为我们以后对xml文件解析的使用。

你可能感兴趣的:(mybatis,xpath)