[jdom-interest] [PATCH] Allow Xslt transformations on documents that require an EntityResolver

Dave Byrne dbyrne at mdb.com
Tue Feb 6 07:38:30 PST 2007


When transforming a Document using XSLTransformer that required an
EntityResolver to be parsed, SAXOutputter.dtdEvents() throws an
exception as it is unable to locate any dtds/entities.

Attached is a patch that adds an additional constructor to JDOMSource
with an EntityResolver which is passed to the internal DocumentReader
allowing the SAXOutputter to properly resolve dtds.

Patch is against cvs HEAD. Any comments are welcomed.

Thanks
Dave Byrne


### Eclipse Workspace Patch 1.0
#P Jdom
Index: src/java/org/jdom/transform/JDOMSource.java
===================================================================
RCS file:
/home/cvspublic/jdom/src/java/org/jdom/transform/JDOMSource.java,v
retrieving revision 1.18
diff -u -r1.18 JDOMSource.java
--- src/java/org/jdom/transform/JDOMSource.java	31 Aug 2004 04:43:48
-0000	1.18
+++ src/java/org/jdom/transform/JDOMSource.java	6 Feb 2007 15:19:58
-0000
@@ -124,6 +124,15 @@
    * @see    #getXMLReader
    */
   private XMLReader xmlReader = null;
+  
+  /**
+   * Optional entity resolver associated to the source of
+   * this document or <code>null</code> if no EntityResolver
+   * was supplied with this JDOMSource. 
+   * 
+   * @see #buildDocumentReader()
+   */
+  private EntityResolver resolver = null;
 
   /**
    * Creates a JDOM TrAX source wrapping a JDOM document.
@@ -168,6 +177,24 @@
   }
 
   /**
+   * Creates a JDOM TrAX source wrapping a JDOM element with an
+   * associated EntityResolver to resolve external entities.
+   * 
+   * @param source 		The JDOM Element to use as source for
the 
+   * 					transformations
+   * 
+   * @param resolver 	Entity resolver to use for the source 
+   * 					transformation
+   * 
+   * @throws IllegalArgumentException	if<code>source</code> is
+   *
<code>null</code>
+   */
+  public JDOMSource(Document source, EntityResolver resolver) {
+	setDocument(source);
+	this.resolver = resolver;
+  }
+
+/**
    * Sets the source document used by this TrAX source.
    *
    * @param  source   the JDOM document to use as source for the
@@ -280,7 +307,7 @@
       while (filter.getParent() instanceof XMLFilter) {
         filter = (XMLFilter)(filter.getParent());
       }
-      filter.setParent(new DocumentReader());
+      filter.setParent(buildDocumentReader());
 
       // Read XML data from filter chain.
       this.xmlReader = reader;
@@ -302,10 +329,25 @@
    */
   public XMLReader getXMLReader() {
     if (this.xmlReader == null) {
-      this.xmlReader = new DocumentReader();
+      this.xmlReader = buildDocumentReader();
     }
     return this.xmlReader;
   }
+  
+  /**
+   * Build an XMLReader to be used for the source. This will
+   * create a new instance of DocumentReader with an 
+   * EntityResolver instance if available.
+   * 
+   * @return XMLReader reading the XML data from the source
+   * 		JDOM document with an optional EntityResolver
+   */
+  private XMLReader buildDocumentReader() {
+	  DocumentReader reader = new DocumentReader();
+	  if(resolver != null)
+		  reader.setEntityResolver(resolver);
+	  return reader;
+  }
 
 
//======================================================================
===
   // JDOMInputSource nested class
Index: src/java/org/jdom/transform/XSLTransformer.java
===================================================================
RCS file:
/home/cvspublic/jdom/src/java/org/jdom/transform/XSLTransformer.java,v
retrieving revision 1.2
diff -u -r1.2 XSLTransformer.java
--- src/java/org/jdom/transform/XSLTransformer.java	6 Feb 2004
09:28:32 -0000	1.2
+++ src/java/org/jdom/transform/XSLTransformer.java	6 Feb 2007
15:19:58 -0000
@@ -61,6 +61,7 @@
 import javax.xml.transform.*;
 import javax.xml.transform.stream.StreamSource;
 import org.jdom.*;
+import org.xml.sax.EntityResolver;
 
 /**
  * A convenience class to handle simple transformations. The JAXP TrAX
classes @@ -219,7 +220,7 @@
             throw new XSLTransformException("Could not perform
transformation", e);
         }
     }
-
+    
     /**
      * Transforms the given document to an output document.
      *
@@ -228,7 +229,19 @@
      * @throws XSLTransformException       if there's a problem in the
transformation
      */
     public Document transform(Document inputDoc) throws
XSLTransformException {
-        JDOMSource source = new JDOMSource(inputDoc);
+    	return transform(inputDoc, null);
+    }
+
+    /**
+     * Transforms the given document to an output document.
+     *
+     * @param  inputDoc            input document
+     * @param  resolver			   entity resolver for
the input document
+     * @return                     transformed output document
+     * @throws XSLTransformException       if there's a problem in the
transformation
+     */
+    public Document transform(Document inputDoc, EntityResolver
resolver) throws XSLTransformException {
+        JDOMSource source = new JDOMSource(inputDoc, resolver);
         JDOMResult result = new JDOMResult();
         try {
             templates.newTransformer().transform(source, result);

//Sample test exposing problem

package test.jdom;

import org.jdom.Document;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.transform.XSLTransformer;


public class TestEntityResolve {

	public static void main(String[] args) throws Exception {
		
		FolderEntityResolver resolver = new
FolderEntityResolver("dtd");
		
		SAXBuilder builder = new SAXBuilder();
		builder.setEntityResolver(resolver);
		Document doc = builder.build(args[0]);
		
		XSLTransformer transformer = new
XSLTransformer(args[1]);

		// will fail with cvs version of jdom		
		//Document outputDoc = transformer.transform(doc);

		//will succeed with patch
		Document outputDoc = transformer.transform(doc,
resolver);

		XMLOutputter out = new
XMLOutputter(Format.getPrettyFormat());
		out.output(outputDoc, System.out);

	}

}

// Sample entity resolver which resolves all entities to files in a
folder package test.jdom;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class FolderEntityResolver implements EntityResolver {
	
	private File folder;

	public FolderEntityResolver(String folderStr) {
		this.folder = new File(folderStr);
	}

	public InputSource resolveEntity(String publicId, String
systemId)
			throws SAXException, IOException {
		File[] files = folder.listFiles();
		
		File srcFile = new File(systemId);
		for(int i = 0; i < files.length; i++) {
			if(files[i].getName().equals(srcFile.getName()))
{
				return new InputSource(new
FileInputStream(files[i]));
			}
		}
		return null;
	}

}


//sample xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo SYSTEM "foo.dtd">
<foo>
	<bar>&entRef;</bar>
</foo>

//sample dtd
<?xml version="1.0" encoding="UTF-8"?>

<!ENTITY entRef    "&#57928;" > <!--UE248 angle with down zig-zag arrow
-->
<!ELEMENT foo   (bar) >
<!ELEMENT bar (#PCDATA)>




More information about the jdom-interest mailing list