2525import org .eclipse .jdt .core .IJavaProject ;
2626import org .eclipse .jdt .core .IPackageFragment ;
2727import org .eclipse .jdt .core .IPackageFragmentRoot ;
28- import org .xml .sax .InputSource ;
28+ import org .xml .sax .Attributes ;
29+ import org .xml .sax .SAXException ;
30+ import org .xml .sax .helpers .DefaultHandler ;
2931import static org .thymeleaf .extras .eclipse .CorePlugin .*;
3032
3133import java .io .IOException ;
3941import java .util .concurrent .Future ;
4042import java .util .concurrent .TimeUnit ;
4143
42- import javax .xml .xpath .XPath ;
43- import javax .xml .xpath .XPathExpression ;
44- import javax .xml .xpath .XPathExpressionException ;
45- import javax .xml .xpath .XPathFactory ;
44+ import javax .xml .parsers .ParserConfigurationException ;
45+ import javax .xml .parsers .SAXParser ;
46+ import javax .xml .parsers .SAXParserFactory ;
4647
4748/**
4849 * Locates Thymeleaf dialect XML help files from a project's dependencies.
5152 */
5253public class ProjectDependencyDialectLocator implements DialectLocator <InputStream > {
5354
55+ private static final String XML_FEATURE_LOAD_DTD_GRAMMAR =
56+ "http://apache.org/xml/features/nonvalidating/load-dtd-grammar" ;
57+ private static final String XML_FEATURE_LOAD_EXTERNAL_DTD =
58+ "http://apache.org/xml/features/nonvalidating/load-external-dtd" ;
59+
5460 private static final String DIALECT_EXTRAS_NAMESPACE = "http://www.thymeleaf.org/extras/dialect" ;
5561
62+ private static final SAXParserFactory parserfactory ;
63+ static {
64+ try {
65+ parserfactory = SAXParserFactory .newInstance ();
66+ parserfactory .setNamespaceAware (true );
67+ parserfactory .setFeature (XML_FEATURE_LOAD_DTD_GRAMMAR , false );
68+ parserfactory .setFeature (XML_FEATURE_LOAD_EXTERNAL_DTD , false );
69+ }
70+ catch (SAXException ex ) {
71+ throw new RuntimeException (ex );
72+ }
73+ catch (ParserConfigurationException ex ) {
74+ throw new RuntimeException (ex );
75+ }
76+ }
77+
5678 private final IJavaProject project ;
57- private final XPathExpression namespaceexpression ;
5879 private final ArrayList <IPath > dialectfilepaths = new ArrayList <IPath >();
5980
6081 /**
@@ -66,14 +87,6 @@ public class ProjectDependencyDialectLocator implements DialectLocator<InputStre
6687 public ProjectDependencyDialectLocator (IJavaProject project ) {
6788
6889 this .project = project ;
69- try {
70- XPathFactory factory = XPathFactory .newInstance ();
71- XPath xpath = factory .newXPath ();
72- namespaceexpression = xpath .compile ("namespace-uri(/*)" );
73- }
74- catch (XPathExpressionException ex ) {
75- throw new RuntimeException (ex );
76- }
7790 }
7891
7992 /**
@@ -96,7 +109,7 @@ public List<IPath> getDialectFilePaths() {
96109 * @return <tt>true</tt> if the resource is an XML file in the
97110 * <tt>http://www.thymeleaf.org/extras/dialect</tt> namespace.
98111 */
99- private boolean isDialectHelpXMLFile (IStorage resource ) {
112+ private static boolean isDialectHelpXMLFile (IStorage resource ) {
100113
101114 InputStream resourcestream = null ;
102115 try {
@@ -106,15 +119,25 @@ private boolean isDialectHelpXMLFile(IStorage resource) {
106119
107120 // Check if the XML file namespace is correct
108121 resourcestream = resource .getContents ();
109- String namespace = namespaceexpression .evaluate (new InputSource (resourcestream ));
110- if (namespace .equals (DIALECT_EXTRAS_NAMESPACE )) {
122+ SAXParser parser = parserfactory .newSAXParser ();
123+ NamespaceHandler handler = new NamespaceHandler ();
124+ parser .parse (resourcestream , handler );
125+ if (handler .namespace != null && handler .namespace .equals (DIALECT_EXTRAS_NAMESPACE )) {
111126 return true ;
112127 }
113128 }
114129 return false ;
115130 }
116- catch (XPathExpressionException ex ) {
117- logError ("Unable to execute XPath expression" , ex );
131+ catch (ParserConfigurationException ex ) {
132+ logError ("Unable to read XML file" , ex );
133+ return false ;
134+ }
135+ catch (IOException ex ) {
136+ logError ("Unable to read XML file" , ex );
137+ return false ;
138+ }
139+ catch (SAXException ex ) {
140+ logError ("Unable to read XML file" , ex );
118141 return false ;
119142 }
120143 catch (CoreException ex ) {
@@ -207,4 +230,28 @@ public IStorage call() throws Exception {
207230 logInfo ("Scanning complete. Execution time: " + (System .currentTimeMillis () - start ) + "ms" );
208231 return dialectstreams ;
209232 }
233+
234+ /**
235+ * Basic SAX handler that cares only about the document namespace.
236+ */
237+ private static class NamespaceHandler extends DefaultHandler {
238+
239+ private String namespace ;
240+
241+ /**
242+ * Saves the document namespace, then does nothing after that.
243+ *
244+ * @param uri
245+ * @param localName
246+ * @param qName
247+ * @param attributes
248+ */
249+ @ Override
250+ public void startElement (String uri , String localName , String qName , Attributes attributes ) {
251+
252+ if (namespace == null ) {
253+ namespace = uri ;
254+ }
255+ }
256+ }
210257}
0 commit comments