xml基础知识
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
">
</beans>
java提供的xml解析工具有:sax/dom/dom4j。Spring用的是dom。
schema,提要,纲要; 用于定义元素和属性的层次结构。
xmlns: xml, name space 名称空间,用于确定标签的一致性。如上面的xmlns="http://www.springframework.org/schema/beans"描述的是beans这个标签的名称空间。
xmlns:xsi=,业界默认的用于XSD(XML Schama Definition)文件的命名空间。业界还有一种校验方式是DTD。
xsi:schamaLocation,以key+value的形式,代表key这个名称空间的schema文件在value这个地方。上面案例表示的意思是<beans> 这个标签的schema文件在http://www.springframework.org/schema/beans/spring-beans-3.1.xsd。
下面代码可以开启对名称空间的校验:
factory.setNamespaceAware(true);
factory.setValidating(true);
// 开启校验这个是必须加的常量
factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
案例:对这个文件xml_parse_demo.xml进行解析
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
">
<context:component-scan base-package="com"/>
<bean class="com.jack.postprocessor.Test">
<property name="mapperScanPostProcessor"/>
</bean>
<bean class="com.jack.postprocessor.ModelService" />
</beans>
解析代码:
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
ClassPathResource resource = new ClassPathResource("xml_parse_demo.xml");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(true);
// 开启校验这个是必须加的常量
factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
// 设置如果 schema无法联网情况下加载本地schema
documentBuilder.setEntityResolver((publicId, systemId) -> {
System.out.println(systemId);
if (systemId.equals("http://www.springframework.org/schema/beans/spring-beans-3.1.xsd")) {
ClassPathResource schama = new ClassPathResource("org/springframework/beans/factory/xml/spring-beans.xsd");
InputSource inputSource = new InputSource(schama.getInputStream());
inputSource.setSystemId(systemId);
return inputSource;
} else if(systemId.equals("http://www.springframework.org/schema/context/spring-context-3.1.xsd")) {
ClassPathResource schama = new ClassPathResource("org/springframework/context/config/spring-context.xsd");
InputSource inputSource = new InputSource(schama.getInputStream());
inputSource.setSystemId(systemId);
return inputSource;
} else if (systemId.equals("http://www.springframework.org/schema/tool/spring-tool.xsd")) {
ClassPathResource schama = new ClassPathResource("org/springframework/beans/factory/xml/spring-tool.xsd");
InputSource inputSource = new InputSource(schama.getInputStream());
inputSource.setSystemId(systemId);
return inputSource;
}
return null;
});
// 设置校验xml时的处理者
documentBuilder.setErrorHandler(new ErrorHandler() {
@Override
public void warning(SAXParseException exception) throws SAXException {
System.out.println(exception.toString());
}
@Override
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
});
// 解析xml
Document document = documentBuilder.parse(resource.getInputStream());
Element root = document.getDocumentElement();
System.out.println(root.getNodeName());
String tab = "";
parse(root, tab + "\t");
}
// 模拟对xml的解析
public static void parse(Node node, String tab) {
NodeList childNodes = node.getChildNodes();
int len = childNodes.getLength();
for (int i = 0; i < len; i++) {
Node childNode = childNodes.item(i);
if (childNode instanceof Element) {
System.out.println(tab + childNode.getNodeName());
parse(childNode, tab + "\t");
}
}
}
我们配置的schema文件是网络文件,如果不联网的情况需要将网络文件替换为本地文件,Spring的schema本地文件的替换信息都配置在META-INF/spring.schemas的文件里面:
org.springframework.beans.factory.xml.ResourceEntityResolver#resolveEntity
public InputSource resolveEntity(String publicId, @Nullable String systemId) throws SAXException, IOException {
InputSource source = super.resolveEntity(publicId, systemId);
if (source == null && systemId != null) {
String resourcePath = null;
try {
String decodedSystemId = URLDecoder.decode(systemId, "UTF-8");
String givenUrl = new URL(decodedSystemId).toString();
String systemRootUrl = new File("").toURI().toURL().toString();
// Try relative to resource base if currently in system root.
if (givenUrl.startsWith(systemRootUrl)) {
resourcePath = givenUrl.substring(systemRootUrl.length());
}
}
catch (Exception ex) {
// Typically a MalformedURLException or AccessControlException.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve XML entity [" + systemId + "] against system root URL", ex);
}
// No URL (or no resolvable URL) -> try relative to resource base.
resourcePath = systemId;
}
if (resourcePath != null) {
if (logger.isTraceEnabled()) {
logger.trace("Trying to locate XML entity [" + systemId + "] as resource [" + resourcePath + "]");
}
Resource resource = this.resourceLoader.getResource(resourcePath);
source = new InputSource(resource.getInputStream());
source.setPublicId(publicId);
source.setSystemId(systemId);
if (logger.isDebugEnabled()) {
logger.debug("Found XML entity [" + systemId + "]: " + resource);
}
}
}
return source;
}
private Map<String, String> getSchemaMappings() {
Map<String, String> schemaMappings = this.schemaMappings;
if (schemaMappings == null) {
synchronized (this) {
schemaMappings = this.schemaMappings;
if (schemaMappings == null) {
if (logger.isDebugEnabled()) {
logger.debug("Loading schema mappings from [" + this.schemaMappingsLocation + "]");
}
try {
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.schemaMappingsLocation, this.classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Loaded schema mappings: " + mappings);
}
schemaMappings = new ConcurrentHashMap<>(mappings.size());
CollectionUtils.mergePropertiesIntoMap(mappings, schemaMappings);
this.schemaMappings = schemaMappings;
}
catch (IOException ex) {
throw new IllegalStateException(
"Unable to load schema mappings from location [" + this.schemaMappingsLocation + "]", ex);
}
}
}
}
return schemaMappings;
}