论坛首页 Java企业应用论坛

关于在DOM4J在读取XML文件时,解释DTD的问题

浏览 10498 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-07-04  

近日在使用 DOM4J 的时候,遇到一个问题,现在有两个解决方法,先记下来,以便日后使用。

问题:对一个 XML 文件进行读写操作,但是发现当文件存在的时候,使用DOM4J读进来的时候,生成的 Document 对象会根据 DTD 里的定义,追加了一些 default 属性(实际不需要)。而且在读取的时间被延长。


有一个 XML 文件如下:<o:p></o:p>

xml 代码
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">  
  3.   
  4. <beans>   
  5.   ....  
  6. </beans>  

使用 DOM4J 的读取文件的一般性写法:<o:p></o:p>

java 代码
 
  1. SAXReader reader = new SAXReader(false);  
  2. document = reader.read(file);  
  3. root = document.getRootElement();  

对象 document 里的节点会被自动追加 DTD 里的定义的 default 属性,只有新增加的节点不受影响,如下。而且,如果文件的操作时间被延长。

xml 代码
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">  
  3.   
  4. <beans default-lazy-init="false" default-autowire="no" default-dependency-check="none">   
  5.   <bean id="OperateXmlByDom4jTestCase" class="test.OperateXmlByDom4jTestCase" lazy-init="default" autowire="default" dependency-check="default"/>    
  6.   <bean id="OperateXmlByDom4jTestCase" class="test.OperateXmlByDom4jTestCase" lazy-init="default" autowire="default" dependency-check="default"/>    
  7.   <bean id="OperateXmlByDom4jTestCase" class="test.OperateXmlByDom4jTestCase" lazy-init="default" autowire="default" dependency-check="default"/>    
  8.   <bean id="OperateXmlByDom4jTestCase" class="test.OperateXmlByDom4jTestCase" lazy-init="default" autowire="default" dependency-check="default"/>    
  9.   <bean id="OperateXmlByDom4jTestCase" class="test.OperateXmlByDom4jTestCase" lazy-init="default" autowire="default" dependency-check="default"/>    
  10.   <bean id="OperateXmlByDom4jTestCase" class="test.OperateXmlByDom4jTestCase" lazy-init="default" autowire="default" dependency-check="default"/>    
  11.   <bean id="OperateXmlByDom4jTestCase" class="test.OperateXmlByDom4jTestCase" lazy-init="default" autowire="default" dependency-check="default"/>    
  12.   <bean id="OperateXmlByDom4jTestCase" class="test.OperateXmlByDom4jTestCase"/>    
  13.   <bean id="OperateXmlByDom4jTestCase" class="test.OperateXmlByDom4jTestCase"/>    
  14.   <bean id="OperateXmlByDom4jTestCase" class="test.OperateXmlByDom4jTestCase"/>  
  15. </beans>  
<o:p></o:p>

为了不让生成我们不需要的 default 属性和缩短文件的操作时间,我们可以调用 SAXReader.setFeature 方法来改变 DOM4J 的行为,片断代码如下:<o:p></o:p>

java 代码
 
  1. // http://apache.org/xml/features/nonvalidating/load-external-dtd"  
  2. saxReader.setFeature(  
  3.     Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE,   
  4.     false);  

关于更多的 Feature 请参考 com.sun.org.apache.xerces.internal.impl.Constants<o:p></o:p>

以下为片断代码:<o:p></o:p>

java 代码
 
  1. // xerces features  
  2.   
  3. /** Xerces features prefix ("http://apache.org/xml/features/"). */  
  4. public static final String XERCES_FEATURE_PREFIX = "http://apache.org/xml/features/";  
  5.   
  6. /** Schema validation feature ("validation/schema"). */  
  7. public static final String SCHEMA_VALIDATION_FEATURE = "validation/schema";  
  8.   
  9. /** Expose schema normalized values */  
  10. public static final String SCHEMA_NORMALIZED_VALUE = "validation/schema/normalized-value";  
  11.   
  12. /** Send schema default value via characters() */  
  13. public static final String SCHEMA_ELEMENT_DEFAULT = "validation/schema/element-default";  
  14.   
  15. /** Schema full constraint checking ("validation/schema-full-checking"). */  
  16. public static final String SCHEMA_FULL_CHECKING = "validation/schema-full-checking";  
  17.   
  18. /** Augment Post-Schema-Validation-Infoset */  
  19. public static final String SCHEMA_AUGMENT_PSVI = "validation/schema/augment-psvi";  
  20.   
  21. /** Dynamic validation feature ("validation/dynamic"). */  
  22. public static final String DYNAMIC_VALIDATION_FEATURE = "validation/dynamic";  
  23.   
  24. /** Warn on duplicate attribute declaration feature ("validation/warn-on-duplicate-attdef"). */  
  25. public static final String WARN_ON_DUPLICATE_ATTDEF_FEATURE = "validation/warn-on-duplicate-attdef";  
  26.   
  27. /** Warn on undeclared element feature ("validation/warn-on-undeclared-elemdef"). */  
  28. public static final String WARN_ON_UNDECLARED_ELEMDEF_FEATURE = "validation/warn-on-undeclared-elemdef";  
  29.   
  30. /** Warn on duplicate entity declaration feature ("warn-on-duplicate-entitydef"). */  
  31. public static final String WARN_ON_DUPLICATE_ENTITYDEF_FEATURE = "warn-on-duplicate-entitydef";  
  32.   
  33. /** Allow Java encoding names feature ("allow-java-encodings"). */  
  34. public static final String ALLOW_JAVA_ENCODINGS_FEATURE = "allow-java-encodings";  
  35.   
  36. /** Disallow DOCTYPE declaration feature ("disallow-doctype-decl"). */  
  37. public static final String DISALLOW_DOCTYPE_DECL_FEATURE = "disallow-doctype-decl";  
  38.   
  39. /** Continue after fatal error feature ("continue-after-fatal-error"). */  
  40. public static final String CONTINUE_AFTER_FATAL_ERROR_FEATURE = "continue-after-fatal-error";  
  41.   
  42. /** Load dtd grammar when nonvalidating feature ("nonvalidating/load-dtd-grammar"). */  
  43. public static final String LOAD_DTD_GRAMMAR_FEATURE = "nonvalidating/load-dtd-grammar";  
  44.   
  45. /** Load external dtd when nonvalidating feature ("nonvalidating/load-external-dtd"). */  
  46. public static final String LOAD_EXTERNAL_DTD_FEATURE = "nonvalidating/load-external-dtd";  
  47.   
  48. /** Defer node expansion feature ("dom/defer-node-expansion"). */  
  49. public static final String DEFER_NODE_EXPANSION_FEATURE = "dom/defer-node-expansion";  
  50.   
  51. /** Create entity reference nodes feature ("dom/create-entity-ref-nodes"). */  
  52. public static final String CREATE_ENTITY_REF_NODES_FEATURE = "dom/create-entity-ref-nodes";  
  53.   
  54. /** Include ignorable whitespace feature ("dom/include-ignorable-whitespace"). */  
  55. public static final String INCLUDE_IGNORABLE_WHITESPACE = "dom/include-ignorable-whitespace";  
  56.   
  57. /** Default attribute values feature ("validation/default-attribute-values"). */  
  58. public static final String DEFAULT_ATTRIBUTE_VALUES_FEATURE = "validation/default-attribute-values";  
  59.   
  60. /** Validate content models feature ("validation/validate-content-models"). */  
  61. public static final String VALIDATE_CONTENT_MODELS_FEATURE = "validation/validate-content-models";  
  62.   
  63. /** Validate datatypes feature ("validation/validate-datatypes"). */  
  64. public static final String VALIDATE_DATATYPES_FEATURE = "validation/validate-datatypes";  
  65.   
  66. /** Notify character references feature (scanner/notify-char-refs"). */  
  67. public static final String NOTIFY_CHAR_REFS_FEATURE = "scanner/notify-char-refs"; 
  68.  
  69. /** Notify built-in (&, etc.) references feature (scanner/notify-builtin-refs"). */  
  70. public static final String NOTIFY_BUILTIN_REFS_FEATURE = "scanner/notify-builtin-refs";  
  71.   
  72. /** Standard URI conformant feature ("standard-uri-conformant"). */  
  73. public static final String STANDARD_URI_CONFORMANT_FEATURE = "standard-uri-conformant";  
  74.   
  75. /** Internal performance related feature:  
  76.  * false - the parser settings (features/properties) have not changed between 2 parses 
  77.  * true - the parser settings have changed between 2 parses   
  78.  * NOTE: this feature should only be set by the parser configuration. 
  79.  */  
  80. public static final String PARSER_SETTINGS = "internal/parser-settings";  
  81.   
  82. /** Feature to make XML Processor XInclude Aware */  
  83. public static final String XINCLUDE_AWARE = "xinclude-aware";  
  84.   
  85. /** Ignore xsi:schemaLocation and xsi:noNamespaceSchemaLocation. */  
  86. public static final String IGNORE_SCHEMA_LOCATION_HINTS = "validation/schema/ignore-schema-location-hints";  
  87.   
  88. /** 
  89.  * When true, the schema processor will change characters events 
  90.  * to ignorableWhitespaces events, when characters are expected to 
  91.  * only contain ignorable whitespaces. 
  92.  */  
  93. public static final String CHANGE_IGNORABLE_CHARACTERS_INTO_IGNORABLE_WHITESPACES =  
  94.     "validation/change-ignorable-characters-into-ignorable-whitespaces";  

除通过上面的 SAXReader.setFeature 文件之外 ,我们还可以通过自己的 EntityResolver 来解决这个问题。<o:p></o:p>

PS:这个方法是从凝香小筑BLOG的一编主题是:Do not resolve DTD files when dom4j read xml file 的文章里看到的。地址:http://blog.csdn.net/lessoft/archive/<st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="20" month="6" year="2007">2007/06/20</st1:chsdate>/1659579.aspx<o:p></o:p>

代码片断如下:<o:p></o:p>

java 代码
 
  1. saxReader.setEntityResolver(new EntityResolver() {  
  2.       
  3.     String emptyDtd = "";  
  4.                       
  5.     ByteArrayInputStream bytels = new ByteArrayInputStream(emptyDtd.getBytes());  
  6.                       
  7.     public InputSource resolveEntity(String publicId, String systemId)   
  8.            throws SAXException, IOException {  
  9.         return new InputSource(bytels);  
  10.     }  
  11. });  



<o:p> </o:p>

完整的代码如下:<o:p></o:p>

java 代码
 
  1. package test;  
  2.   
  3. import java.io.BufferedWriter;  
  4. import java.io.ByteArrayInputStream;  
  5. import java.io.File;  
  6. import java.io.FileWriter;  
  7. import java.io.IOException;  
  8.   
  9. import junit.framework.TestCase;  
  10.   
  11. import org.dom4j.Document;  
  12. import org.dom4j.DocumentHelper;  
  13. import org.dom4j.Element;  
  14. import org.dom4j.io.OutputFormat;  
  15. import org.dom4j.io.SAXReader;  
  16. import org.dom4j.io.XMLWriter;  
  17. import org.dom4j.tree.DefaultDocumentType;  
  18. import org.xml.sax.EntityResolver;  
  19. import org.xml.sax.InputSource;  
  20. import org.xml.sax.SAXException;  
  21.   
  22. import com.sun.org.apache.xerces.internal.impl.Constants;  
  23.   
  24. /** 
  25.  * A test case class for read and writer a xml file by Dom4j. 
  26.  * @author X.F.Yang [2007/07/03] 
  27.  * @version 1.0 
  28.  */  
  29. public class OperateXmlByDom4jTestCase extends TestCase {  
  30.   
  31.     /** 
  32.      * Default way to read and writer a xml file by Dom4j. 
  33.      * @throws Exception 
  34.      */  
  35.     public void testWriteXml() throws Exception {  
  36.         XmlFileOperation operation = new XmlFileOperation();  
  37.         operation.writer(new SAXReaderWrapper() {  
  38.             public void operation(SAXReader saxReader) throws Exception {  
  39.                 // Nothing to do.  
  40.             }  
  41.         });  
  42.     }  
  43.   
  44.     /** 
  45.      * Do not resolve DTD files when dom4j read xml file via the set feature.  
  46.      * @throws Exception 
  47.      */  
  48.     public void testWriteXmlSetFeature() throws Exception {  
  49.         XmlFileOperation operation = new XmlFileOperation();  
  50.         operation.writer(new SAXReaderWrapper() {  
  51.             public void operation(SAXReader saxReader) throws Exception {  
  52.                 // http://apache.org/xml/features/nonvalidating/load-external-dtd"  
  53.                 saxReader.setFeature(  
  54.                         Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE,   
  55.                         false);  
  56.             }  
  57.         });  
  58.     }  
  59.       
  60.     /** 
  61.      * Do not resolve DTD files when dom4j read xml file via implement {@link EntityResolver}.  
  62.      * @throws Exception 
  63.      */  
  64.     public void testWriteXmlEntityResolver() throws Exception {  
  65.         XmlFileOperation operation = new XmlFileOperation();  
  66.         operation.writer(new SAXReaderWrapper() {  
  67.             public void operation(SAXReader saxReader) throws Exception {  
  68.                 saxReader.setEntityResolver(new EntityResolver() {  
  69.                       
  70.                     String emptyDtd = ""; 
  71.                      
  72.                     ByteArrayInputStream bytels = new ByteArrayInputStream(emptyDtd.getBytes()); 
  73.                      
  74.                     public InputSource resolveEntity(String publicId, 
  75.                             String systemId) throws SAXException, IOException { 
  76.                         return new InputSource(bytels); 
  77.                     } 
  78.                 }); 
  79.             } 
  80.         }); 
  81.     } 
  82.      
  83.     /** */ 
  84.     protected interface SAXReaderWrapper { 
  85.          
  86.         /** operation {@link SAXReader} */ 
  87.         void operation(SAXReader saxReader) throws Exception; 
  88.          
  89.     } 
  90.      
  91.     /**  
  92.      * when the target file was existed, read and append the new element. 
  93.      * else, create a new xml file and add the new element. 
  94.      */ 
  95.     protected class XmlFileOperation { 
  96.          
  97.         /** target file */ 
  98.         private File file; 
  99.          
  100.         public XmlFileOperation() { 
  101.             // target file 
  102.             file = new File("d:\\spring.xml"); 
  103.         } 
  104.          
  105.         /** 
  106.          * Write xml file 
  107.          * @param wrapper  
  108.          * @throws Exception 
  109.          * @see {@link SAXReaderWrapper} 
  110.          */ 
  111.         public void writer(SAXReaderWrapper wrapper) throws Exception { 
  112.             try { 
  113.                 Document document = null; 
  114.                 Element root = null; 
  115.                  
  116.                 // read the xml file if target file was existed  
  117.                 if (file.exists()) { 
  118.                     SAXReader reader = new SAXReader(false); 
  119.                      
  120.                     wrapper.operation(reader); 
  121.                      
  122.                     document = reader.read(file); 
  123.                     root = document.getRootElement(); 
  124.                 // if the target file was not existed, create a new one 
  125.                 } else { 
  126.                     document = DocumentHelper.createDocument(); 
  127.                     document.setDocType(new DefaultDocumentType("beans",  
  128.                             "-//SPRING//DTD BEAN//EN",   
  129.                             "http://www.springframework.org/dtd/spring-beans.dtd"));  
  130.                     root = document.addElement("beans"); 
  131.                 } 
  132.                 // create the element under the root element 
  133.                 root.addElement("bean") 
  134.                     .addAttribute("id", "OperateXmlByDom4jTestCase") 
  135.                     .addAttribute("class", "test.OperateXmlByDom4jTestCase");  
  136.                   
  137.                 // writer the document  
  138.                 writer(document);  
  139.             } catch (Exception e) {  
  140.                 e.printStackTrace();  
  141.                 throw e;  
  142.             }  
  143.         }  
  144.           
  145.         protected void writer(Document document) throws Exception {  
  146.             XMLWriter xmlWriter = null;  
  147.             try {  
  148.                 final OutputFormat format = OutputFormat.createPrettyPrint();  
  149.                 xmlWriter = new XMLWriter(new BufferedWriter(new FileWriter(file)), format);  
  150.                 xmlWriter.write(document);  
  151.             } finally {  
  152.                 if (null != xmlWriter) {  
  153.                     xmlWriter.flush();  
  154.                     xmlWriter.close();  
  155.                 }  
  156.             }  
  157.         }  
  158.     }  
  159. }  
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics