首页 > 代码库 > spring中解析xml
spring中解析xml
解析xml有SAX,Stax,dom等方式,那么spring中是如何解析xml文件的呢?
Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
spring中采用的DOM的方式,所要做的一切就是得到org.w3c.dom.Document对象
上面的documentLoader是DefaultDocumentLoader对象
/* * Copyright 2002-2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.beans.factory.xml;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.util.xml.XmlValidationModeDetector;import org.w3c.dom.Document;import org.xml.sax.EntityResolver;import org.xml.sax.ErrorHandler;import org.xml.sax.InputSource;/** * Spring‘s default {@link DocumentLoader} implementation. * * <p>Simply loads {@link Document documents} using the standard JAXP-configured * XML parser. If you want to change the {@link DocumentBuilder} that is used to * load documents, then one strategy is to define a corresponding Java system property * when starting your JVM. For example, to use the Oracle {@link DocumentBuilder}, * you might start your application like as follows: * * <pre code="class">java -Djavax.xml.parsers.DocumentBuilderFactory=oracle.xml.jaxp.JXDocumentBuilderFactory MyMainClass</pre> * * @author Rob Harrop * @author Juergen Hoeller * @since 2.0 */public class DefaultDocumentLoader implements DocumentLoader { /** * JAXP attribute used to configure the schema language for validation. */ private static final String SCHEMA_LANGUAGE_ATTRIBUTE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; /** * JAXP attribute value indicating the XSD schema language. */ private static final String XSD_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema"; private static final Log logger = LogFactory.getLog(DefaultDocumentLoader.class); /** * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured * XML parser. */ public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); if (logger.isDebugEnabled()) { logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]"); } DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); return builder.parse(inputSource); } /** * Create the {@link DocumentBuilderFactory} instance. * @param validationMode the type of validation: {@link XmlValidationModeDetector#VALIDATION_DTD DTD} * or {@link XmlValidationModeDetector#VALIDATION_XSD XSD}) * @param namespaceAware whether the returned factory is to provide support for XML namespaces * @return the JAXP DocumentBuilderFactory * @throws ParserConfigurationException if we failed to build a proper DocumentBuilderFactory */ protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware) throws ParserConfigurationException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(namespaceAware); if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) { factory.setValidating(true); if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) { // Enforce namespace aware for XSD... factory.setNamespaceAware(true); try { factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE); } catch (IllegalArgumentException ex) { ParserConfigurationException pcex = new ParserConfigurationException( "Unable to validate using XSD: Your JAXP provider [" + factory + "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " + "Upgrade to Apache Xerces (or Java 1.5) for full XSD support."); pcex.initCause(ex); throw pcex; } } } return factory; } /** * Create a JAXP DocumentBuilder that this bean definition reader * will use for parsing XML documents. Can be overridden in subclasses, * adding further initialization of the builder. * @param factory the JAXP DocumentBuilderFactory that the DocumentBuilder * should be created with * @param entityResolver the SAX EntityResolver to use * @param errorHandler the SAX ErrorHandler to use * @return the JAXP DocumentBuilder * @throws ParserConfigurationException if thrown by JAXP methods */ protected DocumentBuilder createDocumentBuilder( DocumentBuilderFactory factory, EntityResolver entityResolver, ErrorHandler errorHandler) throws ParserConfigurationException { DocumentBuilder docBuilder = factory.newDocumentBuilder(); if (entityResolver != null) { docBuilder.setEntityResolver(entityResolver); } if (errorHandler != null) { docBuilder.setErrorHandler(errorHandler); } return docBuilder; }}
loadDocument中有一个参数entityResolver,类型是EntityResolver,这也没有什么,DocumentBuilder本来就可以设置setEntityResolver,那么现在这个entityResolver是什么对象呢?是
DelegatingEntityResolver ,
/* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.beans.factory.xml;import java.io.IOException;import org.springframework.util.Assert;import org.xml.sax.EntityResolver;import org.xml.sax.InputSource;import org.xml.sax.SAXException;/** * {@link EntityResolver} implementation that delegates to a {@link BeansDtdResolver} * and a {@link PluggableSchemaResolver} for DTDs and XML schemas, respectively. * * @author Rob Harrop * @author Juergen Hoeller * @author Rick Evans * @since 2.0 * @see BeansDtdResolver * @see PluggableSchemaResolver */public class DelegatingEntityResolver implements EntityResolver { /** Suffix for DTD files */ public static final String DTD_SUFFIX = ".dtd"; /** Suffix for schema definition files */ public static final String XSD_SUFFIX = ".xsd"; private final EntityResolver dtdResolver; private final EntityResolver schemaResolver; /** * Create a new DelegatingEntityResolver that delegates to * a default {@link BeansDtdResolver} and a default {@link PluggableSchemaResolver}. * <p>Configures the {@link PluggableSchemaResolver} with the supplied * {@link ClassLoader}. * @param classLoader the ClassLoader to use for loading * (can be {@code null}) to use the default ClassLoader) */ public DelegatingEntityResolver(ClassLoader classLoader) { this.dtdResolver = new BeansDtdResolver(); this.schemaResolver = new PluggableSchemaResolver(classLoader); } /** * Create a new DelegatingEntityResolver that delegates to * the given {@link EntityResolver EntityResolvers}. * @param dtdResolver the EntityResolver to resolve DTDs with * @param schemaResolver the EntityResolver to resolve XML schemas with */ public DelegatingEntityResolver(EntityResolver dtdResolver, EntityResolver schemaResolver) { Assert.notNull(dtdResolver, "‘dtdResolver‘ is required"); Assert.notNull(schemaResolver, "‘schemaResolver‘ is required"); this.dtdResolver = dtdResolver; this.schemaResolver = schemaResolver; } public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { if (systemId != null) { if (systemId.endsWith(DTD_SUFFIX)) { return this.dtdResolver.resolveEntity(publicId, systemId); } else if (systemId.endsWith(XSD_SUFFIX)) { return this.schemaResolver.resolveEntity(publicId, systemId); } } return null; } @Override public String toString() { return "EntityResolver delegating " + XSD_SUFFIX + " to " + this.schemaResolver + " and " + DTD_SUFFIX + " to " + this.dtdResolver; }}
在DocumentBuilder调用parse方法的时候会调用EntityResolver(这里是DelegatingEntityResolver)的resolveEntity方法:
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { if (systemId != null) { if (systemId.endsWith(DTD_SUFFIX)) { return this.dtdResolver.resolveEntity(publicId, systemId); } else if (systemId.endsWith(XSD_SUFFIX)) { return this.schemaResolver.resolveEntity(publicId, systemId); } } return null; }
请注意resolveEntity方法会根据systemId来返回不同的对象,systemId即是xsi:schemaLocation种的值
/* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.beans.factory.xml;import java.io.FileNotFoundException;import java.io.IOException;import java.util.Map;import java.util.Properties;import java.util.concurrent.ConcurrentHashMap;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;import org.springframework.core.io.support.PropertiesLoaderUtils;import org.springframework.util.Assert;import org.springframework.util.CollectionUtils;import org.xml.sax.EntityResolver;import org.xml.sax.InputSource;/** * {@link EntityResolver} implementation that attempts to resolve schema URLs into * local {@link ClassPathResource classpath resources} using a set of mappings files. * * <p>By default, this class will look for mapping files in the classpath using the pattern: * {@code META-INF/spring.schemas} allowing for multiple files to exist on the * classpath at any one time. * * The format of {@code META-INF/spring.schemas} is a properties * file where each line should be of the form {@code systemId=schema-location} * where {@code schema-location} should also be a schema file in the classpath. * Since systemId is commonly a URL, one must be careful to escape any ‘:‘ characters * which are treated as delimiters in properties files. * * <p>The pattern for the mapping files can be overidden using the * {@link #PluggableSchemaResolver(ClassLoader, String)} constructor * * @author Rob Harrop * @author Juergen Hoeller * @since 2.0 */public class PluggableSchemaResolver implements EntityResolver { /** * The location of the file that defines schema mappings. * Can be present in multiple JAR files. */ public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas"; private static final Log logger = LogFactory.getLog(PluggableSchemaResolver.class); private final ClassLoader classLoader; private final String schemaMappingsLocation; /** Stores the mapping of schema URL -> local schema path */ private volatile Map<String, String> schemaMappings; /** * Loads the schema URL -> schema file location mappings using the default * mapping file pattern "META-INF/spring.schemas". * @param classLoader the ClassLoader to use for loading * (can be {@code null}) to use the default ClassLoader) * @see PropertiesLoaderUtils#loadAllProperties(String, ClassLoader) */ public PluggableSchemaResolver(ClassLoader classLoader) { this.classLoader = classLoader; this.schemaMappingsLocation = DEFAULT_SCHEMA_MAPPINGS_LOCATION; } /** * Loads the schema URL -> schema file location mappings using the given * mapping file pattern. * @param classLoader the ClassLoader to use for loading * (can be {@code null}) to use the default ClassLoader) * @param schemaMappingsLocation the location of the file that defines schema mappings * (must not be empty) * @see PropertiesLoaderUtils#loadAllProperties(String, ClassLoader) */ public PluggableSchemaResolver(ClassLoader classLoader, String schemaMappingsLocation) { Assert.hasText(schemaMappingsLocation, "‘schemaMappingsLocation‘ must not be empty"); this.classLoader = classLoader; this.schemaMappingsLocation = schemaMappingsLocation; } public InputSource resolveEntity(String publicId, String systemId) throws IOException { if (logger.isTraceEnabled()) { logger.trace("Trying to resolve XML entity with public id [" + publicId + "] and system id [" + systemId + "]"); } if (systemId != null) { String resourceLocation = getSchemaMappings().get(systemId); if (resourceLocation != null) { Resource resource = new ClassPathResource(resourceLocation, this.classLoader); try { InputSource source = new InputSource(resource.getInputStream()); source.setPublicId(publicId); source.setSystemId(systemId); if (logger.isDebugEnabled()) { logger.debug("Found XML schema [" + systemId + "] in classpath: " + resourceLocation); } return source; } catch (FileNotFoundException ex) { if (logger.isDebugEnabled()) { logger.debug("Couldn‘t find XML schema [" + systemId + "]: " + resource, ex); } } } } return null; } /** * Load the specified schema mappings lazily. */ private Map<String, String> getSchemaMappings() { if (this.schemaMappings == null) { synchronized (this) { if (this.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); } Map<String, String> schemaMappings = new ConcurrentHashMap<String, String>(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 this.schemaMappings; } @Override public String toString() { return "EntityResolver using mappings " + getSchemaMappings(); }}
/* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.beans.factory.xml;import java.io.IOException;import java.util.Arrays;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;import org.xml.sax.EntityResolver;import org.xml.sax.InputSource;/** * EntityResolver implementation for the Spring beans DTD, * to load the DTD from the Spring class path (or JAR file). * * <p>Fetches "spring-beans-2.0.dtd" from the class path resource * "/org/springframework/beans/factory/xml/spring-beans-2.0.dtd", * no matter whether specified as some local URL that includes "spring-beans" * in the DTD name or as "http://www.springframework.org/dtd/spring-beans-2.0.dtd". * * @author Juergen Hoeller * @author Colin Sampaleanu * @since 04.06.2003 * @see ResourceEntityResolver */public class BeansDtdResolver implements EntityResolver { private static final String DTD_EXTENSION = ".dtd"; private static final String[] DTD_NAMES = {"spring-beans-2.0", "spring-beans"}; private static final Log logger = LogFactory.getLog(BeansDtdResolver.class); public InputSource resolveEntity(String publicId, String systemId) throws IOException { if (logger.isTraceEnabled()) { logger.trace("Trying to resolve XML entity with public ID [" + publicId + "] and system ID [" + systemId + "]"); } if (systemId != null && systemId.endsWith(DTD_EXTENSION)) { int lastPathSeparator = systemId.lastIndexOf("/"); for (String DTD_NAME : DTD_NAMES) { int dtdNameStart = systemId.indexOf(DTD_NAME); if (dtdNameStart > lastPathSeparator) { String dtdFile = systemId.substring(dtdNameStart); if (logger.isTraceEnabled()) { logger.trace("Trying to locate [" + dtdFile + "] in Spring jar"); } try { Resource resource = new ClassPathResource(dtdFile, getClass()); InputSource source = new InputSource(resource.getInputStream()); source.setPublicId(publicId); source.setSystemId(systemId); if (logger.isDebugEnabled()) { logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile); } return source; } catch (IOException ex) { if (logger.isDebugEnabled()) { logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in class path", ex); } } } } } // Use the default behavior -> download from website or wherever. return null; } @Override public String toString() { return "EntityResolver for DTDs " + Arrays.toString(DTD_NAMES); }}
在PluggableSchemaResolver类中会去加载META-INF/spring.schemas
http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsdhttp\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsdhttp\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsdhttp\://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsdhttp\://www.springframework.org/schema/beans/spring-beans-3.2.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsdhttp\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsdhttp\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsdhttp\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsdhttp\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsdhttp\://www.springframework.org/schema/tool/spring-tool-3.1.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsdhttp\://www.springframework.org/schema/tool/spring-tool-3.2.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsdhttp\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsdhttp\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsdhttp\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsdhttp\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsdhttp\://www.springframework.org/schema/util/spring-util-3.1.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsdhttp\://www.springframework.org/schema/util/spring-util-3.2.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsdhttp\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsd
然后根据systemId去对象的位置获取对应xsd文件
为什么要设置EntityResolver呢?如果xml文件不符合xsd文件,则解析时候会报错,spring中对这种错误的情况只是报异常而已
/* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.util.xml;import org.apache.commons.logging.Log;import org.xml.sax.ErrorHandler;import org.xml.sax.SAXException;import org.xml.sax.SAXParseException;/** * Simple {@code org.xml.sax.ErrorHandler} implementation: * logs warnings using the given Commons Logging logger instance, * and rethrows errors to discontinue the XML transformation. * * @author Juergen Hoeller * @since 1.2 */public class SimpleSaxErrorHandler implements ErrorHandler { private final Log logger; /** * Create a new SimpleSaxErrorHandler for the given * Commons Logging logger instance. */ public SimpleSaxErrorHandler(Log logger) { this.logger = logger; } public void warning(SAXParseException ex) throws SAXException { logger.warn("Ignored XML validation warning", ex); } public void error(SAXParseException ex) throws SAXException { throw ex; } public void fatalError(SAXParseException ex) throws SAXException { throw ex; }}
spring中解析xml
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。