xpath解析xml
public class XPathParser {
private final Document document;
//是否开启验证
private boolean validation;
//加载本地DTD
private EntityResolver entityResolver;
//Properties标签定义值
private Properties variables;
private XPath xpath;
}
解析DTD
spring专栏有自定义命名空间解析,就不阐述了
public class XMLMapperEntityResolver implements EntityResolver {
//指定mybatis-config.xml的DTD
private static final String IBATIS_CONFIG_SYSTEM = "ibatis-3-config.dtd";
private static final String IBATIS_MAPPER_SYSTEM = "ibatis-3-mapper.dtd";
private static final String MYBATIS_CONFIG_SYSTEM = "mybatis-3-config.dtd";
private static final String MYBATIS_MAPPER_SYSTEM = "mybatis-3-mapper.dtd";
//指定dtd位置
private static final String MYBATIS_CONFIG_DTD = "org/apache/ibatis/builder/xml/mybatis-3-config.dtd";
private static final String MYBATIS_MAPPER_DTD = "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd";
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
try {
if (systemId != null) {
String lowerCaseSystemId = systemId.toLowerCase(Locale.ENGLISH);
//查找sysId指定的DTD文档,并读取
if (lowerCaseSystemId.contains(MYBATIS_CONFIG_SYSTEM) || lowerCaseSystemId.contains(IBATIS_CONFIG_SYSTEM)) {
return getInputSource(MYBATIS_CONFIG_DTD, publicId, systemId);
} else if (lowerCaseSystemId.contains(MYBATIS_MAPPER_SYSTEM) || lowerCaseSystemId.contains(IBATIS_MAPPER_SYSTEM)) {
return getInputSource(MYBATIS_MAPPER_DTD, publicId, systemId);
}
}
return null;
} catch (Exception e) {
throw new SAXException(e.toString());
}
}
}
构造Xpath和document
public XPathParser(String xml) {
//构造时,初始化xpath
commonConstructor(false, null, null);
this.document = createDocument(new InputSource(new StringReader(xml)));
}
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();
}
private Document createDocument(InputSource inputSource) {
// important: this must only be called AFTER common constructor
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setValidating(validation);
factory.setNamespaceAware(false);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(false);
factory.setCoalescing(false);
factory.setExpandEntityReferences(true);
DocumentBuilder builder = factory.newDocumentBuilder();
//设置DTD解析器
builder.setEntityResolver(entityResolver);
builder.setErrorHandler(new ErrorHandler() {
@Override
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void warning(SAXParseException exception) throws SAXException {
// NOP
}
});
//加载XML
return builder.parse(inputSource);
} catch (Exception e) {
throw new BuilderException("Error creating document instance. Cause: " + e, e);
}
}
解析String
public String evalString(Object root, String expression) {
String result = (String) evaluate(expression, root, XPathConstants.STRING);
//设置节点默认值
result = PropertyParser.parse(result, variables);
return result;
}
public static String parse(String string, Properties variables) {
VariableTokenHandler handler = new VariableTokenHandler(variables);
//指定处理的占位符格式为${}
GenericTokenParser parser = new GenericTokenParser("${", "}", handler);
return parser.parse(string);
}
public class GenericTokenParser {
//占位符开始标记
private final String openToken;
//占位符结束标记
private final String closeToken;
//解析占位符
private final TokenHandler handler;
/**
* 将text根据前后占位符解析
* @param text
* @return
*/
public String parse(String text) {
if (text == null || text.isEmpty()) {
return "";
}
// search open token
//查找第一个开启占位符位置
int start = text.indexOf(openToken);
if (start == -1) {
return text;
}
char[] src = text.toCharArray();
int offset = 0;
//线程安全,记录占位符的值
final StringBuilder builder = new StringBuilder();
StringBuilder expression = null;
while (start > -1) {
if (start > 0 && src[start - 1] == '\\') {
// this open token is escaped. remove the backslash and continue.
//遇到转义的开始标记,直接将前面的字符串以及开始标记追加
builder.append(src, offset, start - offset - 1).append(openToken);
offset = start + openToken.length();
} else {
// found open token. let's search close token.
//查找到开始标记,且未转义
if (expression == null) {
expression = new StringBuilder();
} else {
expression.setLength(0);
}
//前面字符追加
builder.append(src, offset, start - offset);
offset = start + openToken.length();
//从offset后继续查找结束标记
int end = text.indexOf(closeToken, offset);
while (end > -1) {
if (end > offset && src[end - 1] == '\\') {
// this close token is escaped. remove the backslash and continue.
//处理转义的结束标记
expression.append(src, offset, end - offset - 1).append(closeToken);
offset = end + closeToken.length();
end = text.indexOf(closeToken, offset);
} else {
//将开始标记和结束标记之间字符添加
expression.append(src, offset, end - offset);
break;
}
}
if (end == -1) {
//未找到结束标记
// close token was not found.
builder.append(src, start, src.length - start);
offset = src.length;
} else {
//将占位符的值交给handler处理,并保存builder
builder.append(handler.handleToken(expression.toString()));
offset = end + closeToken.length();
}
}
//移动start
start = text.indexOf(openToken, offset);
}
if (offset < src.length) {
builder.append(src, offset, src.length - offset);
}
return builder.toString();
}
}
private static class VariableTokenHandler implements TokenHandler {
//Properties标签定义值,用于替换占位符
private final Properties variables;
//是否支持占位符中使用默认的功能
private final boolean enableDefaultValue;
//指定占位符和默认值之间的分隔符
private final String defaultValueSeparator;
@Override
public String handleToken(String content) {
//variables非空
if (variables != null) {
String key = content;
//是否支持占位符中使用默认值功能
if (enableDefaultValue) {
//查找分割符
final int separatorIndex = content.indexOf(defaultValueSeparator);
String defaultValue = null;
if (separatorIndex >= 0) {
//获取占位符名称
key = content.substring(0, separatorIndex);
//获取默认值
defaultValue = content.substring(separatorIndex + defaultValueSeparator.length());
}
if (defaultValue != null) {
//查找指定占位符
return variables.getProperty(key, defaultValue);
}
}
//不支持默认值,则直接找
if (variables.containsKey(key)) {
return variables.getProperty(key);
}
}
//variables空
return "${" + content + "}";
}
}
解析XNode
public List<XNode> evalNodes(Object root, String expression) {
//XNode,mybatis实现,封装node
List<XNode> 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 class XNode {
//w3c对象
private final Node node;
//节点名
private final String name;
//节点内容
private final String body;
//节点属性集合
private final Properties attributes;
//Properties对应配置文件
private final Properties variables;
private final XPathParser xpathParser;
public XNode(XPathParser xpathParser, Node node, Properties variables) {
this.xpathParser = xpathParser;
this.node = node;
this.name = node.getNodeName();
this.variables = variables;
this.attributes = parseAttributes(node);
this.body = parseBody(node);
}
private Properties parseAttributes(Node n) {
Properties attributes = new Properties();
//获取节点的属性集合
NamedNodeMap attributeNodes = n.getAttributes();
if (attributeNodes != null) {
for (int i = 0; i < attributeNodes.getLength(); i++) {
Node attribute = attributeNodes.item(i);
//使用PropertyParser 处理每个属性中的占位符
String value = PropertyParser.parse(attribute.getNodeValue(), variables);
attributes.put(attribute.getNodeName(), value);
}
}
return attributes;
}
private String parseBody(Node node) {
String data = getBodyData(node);
//当前节点不是文本节点
if (data == null) {
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
data = getBodyData(child);
if (data != null) {
break;
}
}
}
return data;
}
private String getBodyData(Node child) {
//只处理文本内容
if (child.getNodeType() == Node.CDATA_SECTION_NODE
|| child.getNodeType() == Node.TEXT_NODE) {
String data = ((CharacterData) child).getData();
//使用PropertyParser 处理文本节点中的占位符
data = PropertyParser.parse(data, variables);
return data;
}
return null;
}
}
对反射支持
public class Reflector {
//对应的Class 类型
private final Class<?> type;
//可读属性的名称集合,可读属性就是存在相应getter 方法的属性,初始值为空数纽
private final String[] readablePropertyNames;
//可写属性的名称集合,可写属性就是存在相应setter 方法的属性,初始值为空数纽
private final String[] writablePropertyNames;
//记录了属性相应的setter 方法, key 是属性名称, value 是Invoker 对象
private final Map<String, Invoker> setMethods = new HashMap<>();
//属性相应的getter 方法集合, key 是属性名称, value 也是Inv o ker 对象
private final Map<String, Invoker> getMethods = new HashMap<>();
//记录了属性相应的setter 方法的参数值类型, ke y 是属性名称, value 是setter 方法的参数类型
private final Map<String, Class<?>> setTypes = new HashMap<>();
//记录了属性相应的getter 方法的返回位类型, key 是属性名称, value 是getter 方法的返回位类型
private final Map<String, Class<?>> getTypes = new HashMap<>();
//记录了默认构造方法
private Constructor<?> defaultConstructor;
//记录了所有属性名称的集合
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
public Reflector(Class<?> clazz) {
type = clazz;
//查找clazz 的默认构造方法(无参构造方法)
addDefaultConstructor(clazz);
//处理clazz 中的getter 方法,填充getMethods 集合和getTypes 集合
addGetMethods(clazz);
//处理clazz 中的set ter 方法,填充setMethods 集合和set Types 集合
addSetMethods(clazz);
//处理没有g etter I setter 方法的字段
addFields(clazz);
//根据getMethodslsetMethods 集合,初始化可读/写属性的名称集合
readablePropertyNames = getMethods.keySet().toArray(new String[0]);
writablePropertyNames = setMethods.keySet().toArray(new String[0]);
//初始化caseinsensitivePropertyMap 集合,其中记录了所有大写格式的属性名称
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
private void addGetMethods(Class<?> clazz) {
Map<String, List<Method>> conflictingGetters = new HashMap<>();
//获取指定类以及其父类和接口中定义的方法
Method[] methods = getClassMethods(clazz);
//对get方法过滤
Arrays.stream(methods).filter(m ->
//JavaBean 中getter 方法的方法名长度大于3 且必须以” get ” 开头
m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName()))
.forEach(m ->
//记录到conflictingGetters集合中
addMethodConflict(conflictingGetters,
//获取对应的属性名称
PropertyNamer.methodToProperty(m.getName()), m));
//对方法同名返回值不一样的处理
resolveGetterConflicts(conflictingGetters);
}
private Method[] getClassMethods(Class<?> clazz) {
//用于记录指定类中定义的全部方法的唯一签名以及对应的Meth od 对象
Map<String, Method> uniqueMethods = new HashMap<>();
Class<?> currentClass = clazz;
while (currentClass != null && currentClass != Object.class) {
//记录currentClass 这个类中定义的全部方法.桥方法除外
addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());
// we also need to look for interface methods -
// because the class may be abstract
//记录接口中定义的方法
Class<?>[] interfaces = currentClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
addUniqueMethods(uniqueMethods, anInterface.getMethods());
}
//获取父类,继续while 循环
currentClass = currentClass.getSuperclass();
}
Collection<Method> methods = uniqueMethods.values();
return methods.toArray(new Method[0]);
}
private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {
for (Method currentMethod : methods) {
//过滤桥接方法,也就是为了兼容泛型,重新定义了一个方法,调用原来的方法,定位桥
if (!currentMethod.isBridge()) {
//方法得到的方法签名是全局唯一的,可以作为该方法 的唯一标识
String signature = getSignature(currentMethod);
// check to see if the method is already known
// if it is known, then an extended class must have
// overridden a method
//检测是否在子类中已经添加过该方法,如果在子类中已经添加过,无须再向uniqueMethods 集合中添加该方法了
if (!uniqueMethods.containsKey(signature)) {
//记录该签名和方法的对应关系
uniqueMethods.put(signature, currentMethod);
}
}
}
}
}
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
for (Entry<String, List<Method>> entry : conflictingGetters.entrySet()) {
Method winner = null;
String propName = entry.getKey();
boolean isAmbiguous = false;
for (Method candidate : entry.getValue()) {
if (winner == null) {
winner = candidate;
continue;
}
//同一属性名称存在多个getter方法,则需要比较这些getter方法的返回,选择getter方法
//迭代过程中的临时变量,用于记录迭代到目前为止,最适合作为getter 方法的Method
Class<?> winnerType = winner.getReturnType();
Class<?> candidateType = candidate.getReturnType();
if (candidateType.equals(winnerType)) {
//对boolean处理
if (!boolean.class.equals(candidateType)) {
isAmbiguous = true;
break;
} else if (candidate.getName().startsWith("is")) {
winner = candidate;
}
} else if (candidateType.isAssignableFrom(winnerType)) {
// OK getter type is descendant
//当前最适合的方法的返回佳是当前方法返回的子类,什么都不做,当前最适合的方法 依然不变
} else if (winnerType.isAssignableFrom(candidateType)) {
//当前方法的返回位是当前最适合的方法的返回值的子类,更新临时交量getter,当前的getter 方法成为最适合的getter 方法
winner = candidate;
} else {
//返回值相同,二义性,抛出异常
isAmbiguous = true;
break;
}
}
//添加到getMethods 集合并填充get Types 集合
addGetMethod(propName, winner, isAmbiguous);
}
}