diff --git a/de.gebit.integrity.dsl.runner.experimentation/ConsoleTestExecutor XML.launch b/de.gebit.integrity.dsl.runner.experimentation/ConsoleTestExecutor XML.launch
index 6590a08cd..388752340 100644
--- a/de.gebit.integrity.dsl.runner.experimentation/ConsoleTestExecutor XML.launch
+++ b/de.gebit.integrity.dsl.runner.experimentation/ConsoleTestExecutor XML.launch
@@ -19,6 +19,7 @@
+
diff --git a/de.gebit.integrity.dsl.runner.experimentation/ConsoleTestExecutor.launch b/de.gebit.integrity.dsl.runner.experimentation/ConsoleTestExecutor.launch
index 99897b253..a5a3fd2db 100644
--- a/de.gebit.integrity.dsl.runner.experimentation/ConsoleTestExecutor.launch
+++ b/de.gebit.integrity.dsl.runner.experimentation/ConsoleTestExecutor.launch
@@ -19,6 +19,8 @@
+
+
diff --git a/de.gebit.integrity.runner/.classpath b/de.gebit.integrity.runner/.classpath
index b9a5b1ec6..8940e61e2 100644
--- a/de.gebit.integrity.runner/.classpath
+++ b/de.gebit.integrity.runner/.classpath
@@ -3,5 +3,6 @@
+
diff --git a/de.gebit.integrity.runner/META-INF/MANIFEST.MF b/de.gebit.integrity.runner/META-INF/MANIFEST.MF
index 35a33ba03..0d9fa52b2 100644
--- a/de.gebit.integrity.runner/META-INF/MANIFEST.MF
+++ b/de.gebit.integrity.runner/META-INF/MANIFEST.MF
@@ -3,7 +3,6 @@ Bundle-ManifestVersion: 2
Bundle-Name: Integrity Test Framework - Test Runner
Bundle-SymbolicName: de.gebit.integrity.runner
Bundle-Version: 0.16.0.qualifier
-Bundle-ClassPath: .
Require-Bundle: org.eclipse.xtext;bundle-version="2.8.3",
de.gebit.integrity.dsl,
org.eclipse.xtext.common.types;bundle-version="2.8.3",
@@ -41,3 +40,5 @@ Import-Package: org.apache.log4j;version="1.2.15",
org.jdom.xpath;version="1.0.0",
org.slf4j;version="1.4.0"
Bundle-Vendor: GEBIT Solutions GmbH
+Bundle-ClassPath: .,
+ saxon/saxon-6.5.5-patched.jar
diff --git a/de.gebit.integrity.runner/build.properties b/de.gebit.integrity.runner/build.properties
index 5113c5fa5..4121fd857 100644
--- a/de.gebit.integrity.runner/build.properties
+++ b/de.gebit.integrity.runner/build.properties
@@ -1,3 +1,4 @@
bin.includes = META-INF/,\
- .
+ .,\
+ saxon/
source.. = src/
diff --git a/de.gebit.integrity.runner/pom.xml b/de.gebit.integrity.runner/pom.xml
index 991712f1e..0d7ef6724 100644
--- a/de.gebit.integrity.runner/pom.xml
+++ b/de.gebit.integrity.runner/pom.xml
@@ -18,6 +18,94 @@
${basedir}/src
+
+ ${project.build.directory}/saxon
+
+
+
+
+ org.codehaus.mojo
+ truezip-maven-plugin
+ 1.2
+
+
+ copy-package
+
+ copy
+
+ validate
+
+ true
+
+ ${basedir}/saxon/saxon-6.5.5-patched.jar/
+ ${project.build.directory}/saxon
+ **/*.class
+
+
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-compiler-plugin
+
+
+ default-compile
+ compile
+
+ compile
+
+
+
+
+ de.gebit.integrity.runner.internaldep
+ saxon
+ 6.5.5
+ ${basedir}/saxon/saxon-6.5.5-patched.jar
+
+
+
+
+
+
+
+
+
+
+
+
+ org.eclipse.m2e
+ lifecycle-mapping
+ 1.0.0
+
+
+
+
+
+
+ org.codehaus.mojo
+
+
+ truezip-maven-plugin
+
+
+ [1.2,)
+
+
+ copy
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/de.gebit.integrity.runner/saxon/com.icl.saxon.output.HTMLEmitter.diff b/de.gebit.integrity.runner/saxon/com.icl.saxon.output.HTMLEmitter.diff
new file mode 100644
index 000000000..f7da21de0
--- /dev/null
+++ b/de.gebit.integrity.runner/saxon/com.icl.saxon.output.HTMLEmitter.diff
@@ -0,0 +1,13 @@
+diff --git a/HTMLEmitter.java b/HTMLEmitter.java
+index 033b585..754b892 100644
+--- a/HTMLEmitter.java
++++ b/HTMLEmitter.java
+@@ -326,7 +326,7 @@ public class HTMLEmitter extends XMLEmitter {
+
+ if (inAttribute) {
+ if (ch[i]=='<') {
+- writer.write('<'); // not escaped
++ writer.write("<"); // escaped
+ } else if (ch[i]=='>') {
+ writer.write(">"); // recommended for older browsers
+ } else if (ch[i]=='&') {
diff --git a/de.gebit.integrity.runner/saxon/saxon-6.5.5-patched.jar b/de.gebit.integrity.runner/saxon/saxon-6.5.5-patched.jar
new file mode 100644
index 000000000..c8705990c
Binary files /dev/null and b/de.gebit.integrity.runner/saxon/saxon-6.5.5-patched.jar differ
diff --git a/de.gebit.integrity.runner/src/de/gebit/integrity/runner/callbacks/xml/XmlWriterTestCallback.java b/de.gebit.integrity.runner/src/de/gebit/integrity/runner/callbacks/xml/XmlWriterTestCallback.java
index cbeb63d5f..790b44a9a 100644
--- a/de.gebit.integrity.runner/src/de/gebit/integrity/runner/callbacks/xml/XmlWriterTestCallback.java
+++ b/de.gebit.integrity.runner/src/de/gebit/integrity/runner/callbacks/xml/XmlWriterTestCallback.java
@@ -11,7 +11,6 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
@@ -558,6 +557,11 @@ public class XmlWriterTestCallback extends AbstractTestRunnerCallback {
protected static final String XSLT_RESOURCE_NAME = System.getProperty(SYSPARAM_XSLT_RESOURCE,
"resource/xhtml.xslt");
+ /**
+ * The XSLT transformer factory property.
+ */
+ protected static final String XSLT_TRANSFORMER_FACTORY_PROPERTY = "javax.xml.transform.TransformerFactory";
+
/**
* Creates a new instance.
*
@@ -1654,13 +1658,26 @@ protected int determineTransformThreadStackSize() {
*/
protected void transformResult(FileOutputStream aTargetStream) {
try {
- if (System.getProperty("javax.xml.transform.TransformerFactory") == null) {
- // Explicitly specify the JRE-bundled XSLT transformer if nothing else was specified via the
- // system property, so we at least know for sure what to expect
- System.setProperty("javax.xml.transform.TransformerFactory",
- "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
- }
+ /*
+ * Explicitly specify the bundled, patched Saxon XSLT transformer. There is a problem with the XML source
+ * data that is copied to the transformed HTML result (into the "xmldata" element): since the output method
+ * for the serializer is set to HTML, Saxon assumes it is okay to not escape the < char in attributes, which
+ * is no problem for HTML, but strict XML requires those to be replaced by their corresponding entities. I
+ * could solve this by outputting strict XML, but that renders the output unrenderable by browsers :-( well,
+ * for some reason I don't fully understand at least, I'm no browser developer. To solve this, I have
+ * patched the HTMLEmitter inside the bundled Saxon XSLT transformer to escape this character as well, which
+ * seems to work just fine with browsers as well as XML parsers (which should then only parse until the end
+ * of the xmldata element - afterwards there's a lot of non-well-formed XML, which actually is HTML,
+ * coming). The mentioned patch is provided in the file com.icl.saxon.output.HTMLEmitter.diff.
+ */
+ String tempOldProperty = System.getProperty(XSLT_TRANSFORMER_FACTORY_PROPERTY);
+ System.setProperty(XSLT_TRANSFORMER_FACTORY_PROPERTY, "com.icl.saxon.TransformerFactoryImpl");
TransformerFactory tempTransformerFactory = TransformerFactory.newInstance();
+ if (tempOldProperty != null) {
+ System.setProperty(XSLT_TRANSFORMER_FACTORY_PROPERTY, tempOldProperty);
+ } else {
+ System.clearProperty(XSLT_TRANSFORMER_FACTORY_PROPERTY);
+ }
Transformer tempTransformer = tempTransformerFactory.newTransformer(new StreamSource(getXsltStream()));
tempTransformer.setOutputProperty(OutputKeys.METHOD, "html");
@@ -1668,107 +1685,7 @@ protected void transformResult(FileOutputStream aTargetStream) {
Source tempSource = new JDOMSource(document);
- /*
- * There is a problem with the XML source data that is copied to the transformed HTML result (into the
- * "xmldata" element): since the output method for the serializer is set to HTML, it seems to inevitably
- * output '<' and '>' in attributes as characters, which is no problem for HTML, but strict XML requires
- * those to be replaced by their corresponding entities. I could solve this by outputting strict XML, but
- * that renders the output unrenderable by browsers :-( well, for some reason I don't fully understand at
- * least, I'm no browser developer. To solve this, the following very ugly hack replaces the characters by
- * their entities in all attribute values inside the xmldata section on a character stream level. That makes
- * the xmldata content valid XML and thus conveniently parseable for example by a SAX parser (just be sure
- * to stop the parsing when reaching the end of that section, because the HTML afterwards definitely doesn't
- * parse as XML!), while keeping viewability on all browsers. It should not have any negative side-effects,
- * apart from being disgusting and everything, but well, this can still be replaced by a more elegant
- * solution if someone comes up with one.
- */
- StreamResult tempResult = new StreamResult(new FilterOutputStream(aTargetStream) {
-
- private final char[] triggerOpenTagName = new char[] { 'x', 'm', 'l', 'd', 'a', 't', 'a' };
-
- private final char[] triggerCloseTagName = new char[] { '/', 'x', 'm', 'l', 'd', 'a', 't', 'a' };
-
- private static final char TRIGGER_TAG_START = '<';
-
- private static final char TRIGGER_TAG_END = '<';
-
- private static final char TRIGGER_ATTRIBUTE = '"';
-
- private boolean insideXmlPart;
-
- private boolean insideAttribute;
-
- private boolean pastXmlPart;
-
- private int tagPosition;
-
- @Override
- public void write(int aByte) throws IOException {
- char tempChar = (char) aByte;
-
- if (!pastXmlPart) {
- if (!insideAttribute) {
- if (tempChar == TRIGGER_TAG_START) {
- tagPosition = 0;
- } else if (tempChar == TRIGGER_TAG_END) {
- tagPosition = -1;
- } else if (tagPosition >= 0) {
- if (insideXmlPart && tempChar == TRIGGER_ATTRIBUTE) {
- insideAttribute = true;
- } else {
- tagPosition++;
- if (insideXmlPart) {
- if (tagPosition < triggerCloseTagName.length - 1) {
- if (tempChar != triggerCloseTagName[tagPosition]) {
- tagPosition = 0;
- }
- } else if (tagPosition == triggerCloseTagName.length - 1) {
- insideXmlPart = false;
- pastXmlPart = true;
- tagPosition = 0;
- }
- } else {
- if (tagPosition < triggerOpenTagName.length - 1) {
- if (tempChar != triggerOpenTagName[tagPosition]) {
- tagPosition = 0;
- }
- } else if (tagPosition == triggerOpenTagName.length - 1) {
- insideXmlPart = true;
- pastXmlPart = false;
- tagPosition = 0;
- }
- }
- }
- }
- } else {
- if (insideXmlPart) {
- if (tempChar == TRIGGER_ATTRIBUTE) {
- insideAttribute = false;
- } else {
- if (tempChar == '<') {
- super.write("<".getBytes("UTF-8"));
- return;
- } else if (tempChar == '>') {
- super.write(">".getBytes("UTF-8"));
- return;
- }
- }
- }
- }
- }
-
- super.write(aByte);
- }
-
- @Override
- public void write(byte[] someBytes, int anOffset, int aLength) throws IOException {
- if (!pastXmlPart) {
- super.write(someBytes, anOffset, aLength);
- } else {
- out.write(someBytes, anOffset, aLength);
- }
- }
- });
+ StreamResult tempResult = new StreamResult(aTargetStream);
tempTransformer.transform(tempSource, tempResult);
} catch (TransformerConfigurationException exc) {