diff --git a/.gitignore b/.gitignore index 7f4426f..93fc145 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,33 @@ # Old temorary source copies *.orig *~ - +build classes target velocity.log - +.gradle #for Eclipse .settings .classpath .project .metadata +# IDE project files +*.iml +*.ipr +*.iws +*.kdevelop +*.kdevelop.pcs +*.kdevelop.filelist +*.kdevses +*.kdev4 +*.cbp +*.pro.user +.idea +CMakeLists.txt.user +Doxyfile +classes +target +temp +jbiServiceUnits +out diff --git a/README.md b/README.md new file mode 100644 index 0000000..b5591f3 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# c14n2 +Canonical XML Version 2.0 java implementation + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..7421ffa --- /dev/null +++ b/build.gradle @@ -0,0 +1,36 @@ +group = 'ru.relex' +description = 'c14n2' + +apply plugin: 'java' + +repositories { + mavenLocal() + mavenCentral() +} + +// buildDir = new File(rootProject.projectDir, "out/") + +dependencies { + testCompile 'org.testng:testng:6.2.1' + testCompile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.6' + testCompile 'com.google.inject:guice:3.0' + testCompile ('org.uncommons:reportng:1.1.2') { + exclude group: 'org.testng', module: 'testng' + } + compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.6' + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.5' + compile 'xalan:xalan:2.7.1' + + //provided (group: 'org.slf4j', name: 'slf4j-api', version: '1.7.6') { + /* This dependency was originally in the Maven provided scope, but the project was not of type war. + This behavior is not yet supported by Gradle, so this dependency has been converted to a compile dependency. + Please review and delete this closure when resolved. */ + //} + //provided(group: 'xalan', name: 'xalan', version: '2.7.1') { + /* This dependency was originally in the Maven provided scope, but the project was not of type war. + This behavior is not yet supported by Gradle, so this dependency has been converted to a compile dependency. + Please review and delete this closure when resolved. */ + //} +} + +test.useTestNG() \ No newline at end of file diff --git a/earth.gif b/earth.gif deleted file mode 100644 index e69de29..0000000 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..13372ae Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..fc9b829 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Dec 28 10:00:20 PST 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..9d82f78 --- /dev/null +++ b/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/pom.xml b/pom.xml index dbbd332..b1888f4 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,10 @@ 4.0.0 - ru.relex c14n2 - 0.0.1-SNAPSHOT jar - + 1.0.0 c14n2 http://maven.apache.org @@ -14,13 +12,14 @@ UTF-8 1.6 1.6 - 2.5 + 2.5 1.1.2 3.0 6.2.1 - 1.6.4 + 1.7.6 2.7.1 - + 3.5 + @@ -64,7 +63,14 @@ org.slf4j slf4j-api ${slf4j.version} + provided + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + org.uncommons @@ -85,6 +91,11 @@ test + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + com.google.inject guice ${guice.version} @@ -97,9 +108,10 @@ test - xalan - xalan - ${xalan.version} + xalan + xalan + ${xalan.version} + provided diff --git a/src/main/java/ru/relex/c14n2/Attribute.java b/src/main/java/ru/relex/c14n2/Attribute.java deleted file mode 100644 index d9d2100..0000000 --- a/src/main/java/ru/relex/c14n2/Attribute.java +++ /dev/null @@ -1,64 +0,0 @@ -package ru.relex.c14n2; - -/** - * The internal representation of the attribute. - */ -class Attribute { - private String prefix; - private String newPrefix; - private String localName; - private String value; - - /** - * Returns the prefix of the qualified name of this attribute. - * - * @return Returns the prefix - */ - public String getPrefix() { - return prefix; - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } - - /** - * Returns the new prefix (in "Prefix rewrite" mode) of the qualified name of - * this attribute. - * - * @return Returns the prefix - */ - public String getNewPrefix() { - return newPrefix; - } - - public void setNewPrefix(String newPrefix) { - this.newPrefix = newPrefix; - } - - /** - * Returns the local part of the qualified name of this attribute. - * - * @return Returns the local name - */ - public String getLocalName() { - return localName; - } - - public void setLocalName(String localName) { - this.localName = localName; - } - - /** - * Returns the value of this attribute. - * - * @return Returns the value - */ - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } -} \ No newline at end of file diff --git a/src/main/java/ru/relex/c14n2/DOMCanonicalizer.java b/src/main/java/ru/relex/c14n2/DOMCanonicalizer.java index c4b217b..ef56c63 100644 --- a/src/main/java/ru/relex/c14n2/DOMCanonicalizer.java +++ b/src/main/java/ru/relex/c14n2/DOMCanonicalizer.java @@ -1,13 +1,10 @@ package ru.relex.c14n2; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; +import java.util.*; -import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import ru.relex.c14n2.util.Parameters; /** * C14N2 canonicalization. @@ -15,14 +12,14 @@ public class DOMCanonicalizer { private DOMCanonicalizerHandler canonicalizer = null; - private Document doc = null; + private Node node = null; private List nodes = new ArrayList(); private List includeList = null; /** * Constructor. * - * @param doc + * @param node * DOM document * @param includeList * inclusion list @@ -33,17 +30,17 @@ public class DOMCanonicalizer { * * @throws Exception */ - private DOMCanonicalizer(Document doc, List includeList, + private DOMCanonicalizer(Node node, List includeList, List excludeList, Parameters params) throws Exception { - if (doc == null) { + if (node == null) { throw new NullPointerException(); } this.includeList = includeList != null && includeList.isEmpty() ? null : includeList; - this.doc = doc; - StringBuffer sb = new StringBuffer(); - canonicalizer = new DOMCanonicalizerHandler( + this.node = node; + StringBuilder sb = new StringBuilder(); + canonicalizer = new DOMCanonicalizerHandler(node, params == null ? new Parameters() : params, excludeList != null && excludeList.isEmpty() ? null : excludeList, sb); } @@ -51,22 +48,22 @@ private DOMCanonicalizer(Document doc, List includeList, /** * Constructor. * - * @param doc + * @param node * DOM document * @param params * canonicalization parameters * * @throws Exception */ - public static String canonicalize(Document doc, Parameters params) + public static String canonicalize(Node node, Parameters params) throws Exception { - return canonicalize(doc, null, null, params); + return canonicalize(node, null, null, params); } /** * Constructor. * - * @param doc + * @param node * DOM document * @param includeList * inclusion list @@ -75,15 +72,15 @@ public static String canonicalize(Document doc, Parameters params) * * @throws Exception */ - public static String canonicalize(Document doc, List includeList, + public static String canonicalize(Node node, List includeList, Parameters params) throws Exception { - return canonicalize(doc, includeList, null, params); + return canonicalize(node, includeList, null, params); } /** * Canonicalization method. * - * @param doc + * @param node * DOM document * @param includeList * inclusion list @@ -96,9 +93,9 @@ public static String canonicalize(Document doc, List includeList, * * @throws Exception */ - public static String canonicalize(Document doc, List includeList, + public static String canonicalize(Node node, List includeList, List excludeList, Parameters params) throws Exception { - return new DOMCanonicalizer(doc, includeList, excludeList, params) + return new DOMCanonicalizer(node, includeList, excludeList, params) .canonicalizeSubTree(); } @@ -111,7 +108,7 @@ public static String canonicalize(Document doc, List includeList, */ private String canonicalizeSubTree() throws Exception { if (includeList == null) { - process(doc); + process(node); } else { processIncludeList(); while (nodes.size() > 0) { @@ -138,8 +135,8 @@ private void processIncludeList() { Collections.sort(allNodes, new Comparator() { @Override public int compare(Node n1, Node n2) { - int l1 = canonicalizer.getNodeDepth(n1); - int l2 = canonicalizer.getNodeDepth(n2); + int l1 = getNodeDepth(n1); + int l2 = getNodeDepth(n2); if (l1 != l2) { return l1 - l2; } else { @@ -174,6 +171,17 @@ public int compare(Node n1, Node n2) { nodes = allNodes; } + protected int getNodeDepth(Node node) { + int i = -1; + Node prnt = node; + do { + i++; + prnt = prnt.getParentNode(); + } while (prnt != null); + return i; + } + + /** * Processing a node. * @@ -183,7 +191,6 @@ public int compare(Node n1, Node n2) { private void process(Node node) { if (canonicalizer.isInExcludeList(node)) return; - switch (node.getNodeType()) { case Node.ELEMENT_NODE: canonicalizer.processElement(node); diff --git a/src/main/java/ru/relex/c14n2/DOMCanonicalizerHandler.java b/src/main/java/ru/relex/c14n2/DOMCanonicalizerHandler.java index 792811c..15547c8 100644 --- a/src/main/java/ru/relex/c14n2/DOMCanonicalizerHandler.java +++ b/src/main/java/ru/relex/c14n2/DOMCanonicalizerHandler.java @@ -1,825 +1,1036 @@ package ru.relex.c14n2; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.xml.utils.ObjectVector; -import org.apache.xpath.compiler.XPathParser; -import org.apache.xpath.objects.XString; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Attr; +import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; +import ru.relex.c14n2.util.*; + +import java.util.*; + +import static ru.relex.c14n2.util.XPathParserStates.*; /** * C14N2 canonicalizer. */ class DOMCanonicalizerHandler { - private static final Logger LOGGER = LoggerFactory - .getLogger(DOMCanonicalizerHandler.class); - - private static final String DEFAULT_NS = ""; - private static final String NS = "xmlns"; - private static final String XML = "xml"; - private static final String XSD = "xsd"; - - private static final String CF = "&#x%s;"; - private static final String C = ":"; - - private List excludeList; - private Parameters parameters; - private StringBuffer outputBuffer; - - private boolean bStart = true; - private boolean bEnd = false; - - private Map> namespaces; - private Map sequentialUriMap = new HashMap(); - private boolean bSequential = false; - - private Map xpathesNsMap = new HashMap(); - - /** - * Constructor. - * - * @param parameters - * canonicalization parameters - * @param excludeList - * inclusion list - * @param outputBuffer - * output - */ - protected DOMCanonicalizerHandler(Parameters parameters, - List excludeList, StringBuffer outputBuffer) { - this.parameters = parameters; - this.outputBuffer = outputBuffer; - this.excludeList = excludeList; - bSequential = parameters.getPrefixRewrite().equals(Parameters.SEQUENTIAL); - - namespaces = new HashMap>(); - - List lst = new ArrayList(); - NamespaceContextParams ncp = new NamespaceContextParams(); - if (bSequential) { - ncp.setNewPrefix(String.format("n%s", 0)); - ncp.setHasOutput(false); - } - lst.add(ncp); - namespaces.put(DEFAULT_NS, lst); - - bStart = true; - bEnd = false; - } - - /** - * Prosessing of element node. - * - * @param node - * element node - */ - protected void processElement(Node node) { - LOGGER.debug("processElement: {}", node); - - if (isInExcludeList(node)) - return; + private static final Logger LOGGER = LoggerFactory + .getLogger(DOMCanonicalizerHandler.class); + + private static final String EMPTY_URI = ""; + private static final String EMPTY_PREFIX = ""; + private static final String XMLNS = "xmlns"; + private static final String XML = "xml"; + private static final String CF = "&#x%s;"; + private static final String C = ":"; + private static final int ID_ARRAY_CAPACITY = 20; + + private static final int PREFIX_ARRAY_CAPACITY = 10; + + private List excludeList; + private Parameters parameters; + private StringBuilder outputBuffer; + + private int nextId; + private HashMap redefinedPrefixesMap; + + private static final boolean PVDNP_MODE = true; + private int nodeDepth = 0; + + // + // firstKey - prefix + // secondKey - url + private PrefixesContainer declaredPrefixes; + + // + // PrefixRewrite none: + // firstKey - prefix + // secondKey - url + // PrefixRewrite sequence: + // firstKey - url + // secondKey - prefix + private PrefixesContainer usedPrefixes; + + + private Set qNameAwareElements; + + private Set qNameAwareQualifiedAttrs; + + private Set qNameAwareXPathElements; + + private Set qNameAwareUnqualifiedAttrs; + + + private boolean bSequential = false; + + private char[] tempXpathStorage; + private char[] tempPrefixStorage; + +// private Map xpathesNsMap = new HashMap(); + + /** + * Constructor. + * + * @param parameters canonicalization parameters + * @param excludeList inclusion list + * @param outputBuffer output + */ + protected DOMCanonicalizerHandler(Node node, Parameters parameters, + List excludeList, StringBuilder outputBuffer) { + this.parameters = parameters; + this.outputBuffer = outputBuffer; + this.excludeList = excludeList; + this.declaredPrefixes = new PrefixesContainer(); + + + + this.usedPrefixes = new PrefixesContainer(); + this.qNameAwareElements = new HashSet(); + this.qNameAwareQualifiedAttrs = new HashSet(); + this.qNameAwareXPathElements = new HashSet(); + this.qNameAwareUnqualifiedAttrs = new HashSet(); + this.redefinedPrefixesMap = new HashMap(); + bSequential = parameters.getPrefixRewrite().equals(Parameters.SEQUENTIAL); + + + loadParentNamespaces(node); + + if (declaredPrefixes.getByFirstKey("") == null) { + // The default namespace is declared by xmlns="...". To make the algorithm simpler this will be treated as a + // namespace declaration whose prefix value is "" i.e. an empty string. + declaredPrefixes.definePrefix("", "", 0); + } + + initQNameAwareElements(); + initQNameAwareQualifiedAttrs(); + initQNameAwareXPathElements(); + initQNameAwareUnqualifiedAttrs(); + } + + private void initQNameAwareUnqualifiedAttrs() { + + for (QNameAwareParameter en : parameters.getQnameAwareUnqualifiedAttributes()) { + String qNameAwareElement = createQName(en.getNs(), en.getParentName(), en.getName()); + qNameAwareUnqualifiedAttrs.add(qNameAwareElement); + } + + } + + private void initQNameAwareQualifiedAttrs() { + for (QNameAwareParameter en : parameters.getQnameAwareQualifiedAttributes()) { + String qNameAwareElement = createQName(en.getNs(), en.getName()); + qNameAwareQualifiedAttrs.add(qNameAwareElement); + } + } + + private void initQNameAwareXPathElements() { + for (QNameAwareParameter en : parameters.getQnameAwareXPathElements()) { + String qNameAwareElement = createQName(en.getNs(), en.getName()); + qNameAwareXPathElements.add(qNameAwareElement); + } + } + + private String createQName(String uri, String localName) { + StringBuffer sb = new StringBuffer("{"); + sb.append(uri); + sb.append("}"); + sb.append(localName); + return sb.toString(); + } + + private String createQName(String uri, String localName, String attrName) { + StringBuilder sb = new StringBuilder(createQName(uri, localName)); + sb.append("/"); + sb.append(attrName); + return sb.toString(); + } + + + private void initQNameAwareElements() { + for (QNameAwareParameter en : parameters.getQnameAwareElements()) { + String qNameAwareElement = createQName(en.getNs(), en.getName()); + qNameAwareElements.add(qNameAwareElement); + } + + } + + /** + * Prosessing of element node. + * + * @param node element node + */ + protected void processElement(Node node) { + LOGGER.debug("processElement: {}", node); + if (isInExcludeList(node)) + return; + nodeDepth++; + addNamespaces(node); + + Set nsDeclarations = new HashSet(); + + evaluateUriVisibility(node, nsDeclarations); + + + List nsDeclarationList = new LinkedList(); + nsDeclarationList.addAll(nsDeclarations); + + if (bSequential) { + // Sort this list of namespace URIs by lexicographic(ascending) order. + Collections.sort(nsDeclarationList, new Comparator() { + @Override + public int compare(NSDeclaration t0, NSDeclaration t1) { + return t0.getUri().compareTo(t1.getUri()); + } + }); + + for (NSDeclaration nsDeclaration : nsDeclarationList) { + int nextId; + String newPrefix; + String uri = nsDeclaration.getUri(); + if (redefinedPrefixesMap.containsKey(uri)) { + newPrefix = redefinedPrefixesMap.get(uri); + nsDeclaration.setPrefix(newPrefix); + } else { + nextId = this.nextId; + this.nextId = nextId + 1; + newPrefix = "n" + nextId; + nsDeclaration.setPrefix(newPrefix); + redefinedPrefixesMap.put(uri, newPrefix); + } + - if (getNodeDepth(node) == 1) { - bStart = false; - } - - List outNSList = processNamespaces(node); - - StringBuffer output = new StringBuffer(); - String prfx = getNodePrefix(node); - NamespaceContextParams ncp = getLastElement(prfx); - String localName = getLocalName(node); - if (namespaces.containsKey(prfx) && !ncp.getNewPrefix().isEmpty()) { - output.append(String.format("<%s:%s", ncp.getNewPrefix(), localName)); - } else { - output.append(String.format("<%s", localName)); - } - - List outAttrsList = processAttributes(node); - - for (int i = outNSList.size() - 1; i > 0; i--) { - NamespaceContextParams ncp1 = outNSList.get(i); - for (int j = 0; j < i; j++) { - NamespaceContextParams ncp2 = outNSList.get(j); - if (ncp1.getNewPrefix().equals(ncp2.getNewPrefix()) - && ncp1.getUri().equals(ncp2.getUri())) { - outNSList.remove(i); - break; - } - } - } - - for (NamespaceContextParams namespace : outNSList) { - if ((prfx.equals(namespace.getPrefix()) && !ncp.getNewPrefix().equals( - namespace.getNewPrefix())) - || outputNSInParent(namespace.getPrefix())) { - ncp.setHasOutput(false); - continue; - } - ncp.setHasOutput(true); - String nsName = namespace.getNewPrefix(); - String nsUri = namespace.getUri(); - if (!nsName.equals(DEFAULT_NS)) { - output.append(String.format(" %s:%s=\"%s\"", NS, nsName, nsUri)); - } else { - output.append(String.format(" %s=\"%s\"", NS, nsUri)); - } - } - - for (Attribute attribute : outAttrsList) { - String attrPrfx = attribute.getPrefix(); - String attrName = attribute.getLocalName(); - String attrValue = attribute.getValue(); - if (!bSequential) { - if (!attrPrfx.equals(DEFAULT_NS)) { - output.append(String.format(" %s:%s=\"%s\"", attrPrfx, attrName, - attrValue)); + usedPrefixes.definePrefix(nsDeclaration.getUri(), newPrefix, nodeDepth); + } + } + + // write to outputBuffer + + // startElement + + String nodeLocalName = getLocalName(node); + String nodePrefix = getNodePrefix(node); + + String nodeUri = getNamespaceURIByPrefix(nodePrefix); + + String newPrefix = getNewPrefix(nodeUri, nodePrefix); + + if (newPrefix == null || newPrefix.isEmpty()) { + outputBuffer.append(String.format("<%s", getLocalName(node))); } else { - output.append(String.format(" %s=\"%s\"", attrName, attrValue)); - } - } else { - if (parameters.getQnameAwareAttributes().size() > 0) { - if (namespaces.containsKey(attrPrfx)) { - NamespaceContextParams attrPrfxNcp = getLastElement(attrPrfx); - for (QNameAwareParameter en : parameters.getQnameAwareAttributes()) { - if (attrName.equals(en.getName()) - && en.getNs().equals(attrPrfxNcp.getUri())) { - int idx = attrValue.indexOf(C); - if (idx > -1) { - String attr_value_prfx = attrValue.substring(0, idx); - if (namespaces.containsKey(attr_value_prfx)) { - attrValue = getLastElement(attr_value_prfx).getNewPrefix() - + C + attrValue.substring(idx + 1); - } + outputBuffer.append(String.format("<%s:%s", newPrefix, getLocalName(node))); + } + + // Sort this list of namespace declaration in lexicographic(ascending) order of prefixes. + // see Collections.sort above + if (!PVDNP_MODE || !bSequential) { + Collections.sort(nsDeclarationList, new Comparator() { + @Override + public int compare(NSDeclaration t0, NSDeclaration t1) { + return t0.getPrefix().compareTo(t1.getPrefix()); + } + }); + } + + + for (NSDeclaration nsDeclaration : nsDeclarationList) { + String nsName = nsDeclaration.getPrefix(); + String nsUri = nsDeclaration.getUri(); + if (!nsName.equals(EMPTY_URI)) { + outputBuffer.append(String.format(" %s:%s=\"%s\"", XMLNS, nsName, nsUri)); + } else { + outputBuffer.append(String.format(" %s=\"%s\"", XMLNS, nsUri)); + } + } + + List outAttrsList = processAttributes(node, nodeUri); + + for (Attribute attribute : outAttrsList) { + + String attrPrfx = attribute.getAttrPrfx(); + String attrName = attribute.getLocalName(); + String attrValue = attribute.getValue(); + if (attribute.isAttributeQualified()) { + String attrQName = createQName(attribute.getUri(), attribute.getLocalName()); + if (this.qNameAwareQualifiedAttrs.contains(attrQName)) { + attrValue = processQNameText(attrValue); + } + } else { + String attrQName = createQName(nodeUri, nodeLocalName, attribute.getLocalName()); + if (this.qNameAwareUnqualifiedAttrs.contains(attrQName)) { + attrValue = processQNameText(attrValue); } - } } - } + + + // According to the xml-c14n: + // "Note: unlike elements, if an attribute doesn't have a prefix, that means it is a locally scoped attribute." + // but we used attributeFormDefault="qualified" + /*if (attrPrfx==null && attribute.getLocalName().startsWith(XML)) { + // The "xml" and "xmlns" prefixes are reserved and have special behavior + outputBuffer.append(String.format(" %s=\"%s\"", attrName, attrValue)); + } else { */ + // xack for xml:AAA attributes + if (XML.equals(attribute.getOldPrefix())) { + outputBuffer.append(String.format(" %s:%s=\"%s\"", attribute.getOldPrefix(), attrName, attrValue)); + continue; + } + + if (attrPrfx.isEmpty()) { + outputBuffer.append(String.format(" %s=\"%s\"", attrName, attrValue)); + } else { + outputBuffer.append(String.format(" %s:%s=\"%s\"", attrPrfx, attrName, attrValue)); + } + //} } - String attrNewPrfx = attribute.getNewPrefix(); - if (!attrPrfx.equals("")) { - output.append(String.format(" %s:%s=\"%s\"", attrNewPrfx, attrName, - attrValue)); + + outputBuffer.append(">"); + } + + private String processQNameText(String text) { + String textPrefix = getTextPrefix(text); + String textUri = getNamespaceURIByPrefix(textPrefix); + String newTextPrefix = getNewPrefix(textUri, textPrefix); + + StringBuffer sb = new StringBuffer(newTextPrefix); + sb.append(C); + sb.append(StringUtils.substring(text, textPrefix.length() + 1)); + return sb.toString(); + } + + private String getNewPrefix(String nodeUri, String nodePrefix) { + if (bSequential) { + return usedPrefixes.getByFirstKey(nodeUri); } else { - output.append(String.format(" %s=\"%s\"", attrName, attrValue)); + return nodePrefix; } - } } - output.append(">"); - outputBuffer.append(output); - } + private String getNamespaceURIByPrefix(String prefix) { + String uri = declaredPrefixes.getByFirstKey(prefix); + if (uri == null) { + LOGGER.error("BUG!!"); + throw new RuntimeException(); + } + return uri; + + } + + private List processAttributes(Node node, String nodeUri) { + + // Sort all the attributes in increasing lexicographic order with namespace URI as the primary key and local name + // as the secondary key (an empty namespace URI is lexicographically least). + + List attributeList = new LinkedList(); + for (int ai = 0; ai < node.getAttributes().getLength(); ai++) { + Node attr = node.getAttributes().item(ai); + + String suffix = getLocalName(attr); + + String prfxNs = getNodePrefix(attr); + + if (XMLNS.equals(prfxNs)) { + continue; + } + Attribute attribute = new Attribute(); + attribute.setOldPrefix(prfxNs); + attribute.setLocalName(getLocalName(attr)); + //Note: unlike elements, if an attribute doesn't have a prefix, that means it is a locally scoped attribute. + if (EMPTY_PREFIX.equals(prfxNs)) { + attribute.setUri(nodeUri); + attribute.setAttributeQualified(false); + } else { + if (!XML.equals(prfxNs)) { + attribute.setUri(getNamespaceURIByPrefix(prfxNs)); + + } else { + // xml:... Canonical XML 2.0 should ignore this declaration. + attribute.setLocalName(suffix); + } + } + attribute.setValue(getAttributeValue(attr.getNodeValue())); - /** - * Completion of processing element node. - * - * @param node - * element node - */ - protected void processEndElement(Node node) { - if (isInExcludeList(node)) - return; - StringBuffer output = new StringBuffer(); - String prfx = getNodePrefix(node); - NamespaceContextParams ncp = getLastElement(prfx); - String localName = getLocalName(node); - if (namespaces.containsKey(prfx) && !ncp.getNewPrefix().isEmpty()) { - output.append(String.format("", ncp.getNewPrefix(), localName)); - } else { - output.append(String.format("", localName)); + // If it is a qualified attribute and the PrefixRewrite parameter is sequential, modify the QName + // of the attribute name to use the new prefix + attribute.setAttrPrfx(attribute.isAttributeQualified() ? getNewPrefix(attribute.getUri(), attribute.getOldPrefix()) : ""); + + attributeList.add(attribute); + } + + // Sort this list of namespace declaration in lexicographic(ascending) order of prefixes. + Comparator comparator = new Comparator() { + @Override + public int compare(Attribute t0, Attribute t1) { + String t0Uri = t0.isAttributeQualified() ? t0.getUri() : " "; + String t1Uri = t1.isAttributeQualified() ? t1.getUri() : " "; + String q0 = createQName(t0Uri, t0.getLocalName()); + String q1 = createQName(t1Uri, t1.getLocalName()); + return q0.compareTo(q1); + } + }; + + Collections.sort(attributeList, comparator); + return attributeList; } - removeNamespaces(node); + private String getAttributeValue(String input) { + String attrValue = input != null ? input : ""; + + attrValue = processText(attrValue, true); + StringBuffer value = new StringBuffer(); + for (int i = 0; i < attrValue.length(); i++) { + char codepoint = attrValue.charAt(i); + if (codepoint == 9 || codepoint == 10 || codepoint == 13) { + value.append(String.format(CF, Integer.toHexString(codepoint) + .toUpperCase())); + } else { + value.append(codepoint); + } + } - if (getNodeDepth(node) == 1) { - bEnd = true; + return value.toString(); } - outputBuffer.append(output); - } + /** + * Completion of processing element node. + * + * @param node element node + */ + protected void processEndElement(Node node) { + if (isInExcludeList(node)) + return; - /** - * Prosessing of text node. - * - * @param node - * text node - */ - protected void processText(Node node) { - LOGGER.debug("processText: {}", node); - if (getNodeDepth(node) < 2) { - return; + String nodePrefix = getNodePrefix(node); + String nodeUri = getNamespaceURIByPrefix(nodePrefix); + + + String elementPrefix = getNewPrefix(nodeUri, nodePrefix); + + if (elementPrefix == null || elementPrefix.isEmpty()) { + outputBuffer.append(String.format("", getLocalName(node))); + } else { + outputBuffer.append(String.format("", elementPrefix, getLocalName(node))); + } + + removeNamespaces(node); + nodeDepth--; } - String text = node.getNodeValue() != null ? node.getNodeValue() : ""; - - text = processText(text, false); - - StringBuffer value = new StringBuffer(); - for (int i = 0; i < text.length(); i++) { - char codepoint = text.charAt(i); - if (codepoint == 13) { - value.append(String.format(CF, Integer.toHexString(codepoint) - .toUpperCase())); - } else { - value.append(codepoint); - } - } - text = value.toString(); - - if (parameters.isTrimTextNodes()) { - boolean b = true; - for (int ai = 0; ai < node.getParentNode().getAttributes().getLength(); ai++) { - Node attr = node.getParentNode().getAttributes().item(ai); - if (isInExcludeList(attr)) - continue; - if (XML.equals(getNodePrefix(attr)) - && "preserve".equals(attr.getNodeValue()) - && getLocalName(attr).equals("space")) { - b = false; - break; - } - } - if (b) { - text = text.trim(); - } - } - - if (parameters.getQnameAwareElements().size() > 0 && bSequential) { - if (text.startsWith(XSD + C)) { - if (namespaces.containsKey(XSD)) { - Node prntNode = node.getParentNode(); - String nodeName = getLocalName(prntNode); - String nodePrefix = getNodePrefix(prntNode); - NamespaceContextParams ncp = getLastElement(XSD); - NamespaceContextParams attrPrfxNcp = getLastElement(nodePrefix); - for (QNameAwareParameter en : parameters.getQnameAwareElements()) { - if (nodeName.equals(en.getName()) - && en.getNs().equals(attrPrfxNcp.getUri())) { - text = ncp.getNewPrefix() + text.substring(XSD.length()); + /** + * Prosessing of text node. + * + * @param node text node + */ + + protected void processText(Node node) { + LOGGER.debug("processText: {}", node); + String text = node.getNodeValue() != null ? node.getNodeValue() : ""; + text = processText(text, false); + + StringBuilder value = new StringBuilder(); + for (int i = 0; i < text.length(); i++) { + char codepoint = text.charAt(i); + if (codepoint == 13) { + value.append(String.format(CF, Integer.toHexString(codepoint) + .toUpperCase())); + } else { + value.append(codepoint); } - } - } - } - } - if (parameters.getQnameAwareXPathElements().size() > 0 && bSequential - && node.getParentNode().getChildNodes().getLength() == 1) { - Node prntNode = node.getParentNode(); - String nodeName = getLocalName(prntNode); - String nodePrefix = getNodePrefix(prntNode); - NamespaceContextParams ncp = getLastElement(nodePrefix); - for (QNameAwareParameter en : parameters.getQnameAwareXPathElements()) { - if (nodeName.equals(en.getName()) && ncp.getUri().equals(en.getNs())) { - String nodeText = node.getTextContent(); - NSContext nsContext = xpathesNsMap.get(nodeText); - List xpathNs = nsContext.getXpathNs(); - StringBuffer sb = new StringBuffer(nodeText.length()); - int baseTextIdx = 0; - if (xpathNs.size() > 0) { - Iterator it = xpathNs.iterator(); - String ns = it.next(); - ObjectVector words = nsContext.getWords(); - for (int i = 0; i < words.size(); i++) { - Object obj = words.elementAt(i); - String word = obj.toString(); - int idx = nodeText.indexOf(word, baseTextIdx); - if (idx != baseTextIdx) { - sb.append(nodeText.substring(baseTextIdx, idx)); - baseTextIdx = idx; - } - if (!(obj instanceof XString) - && ns.equals(word) - && (i != words.size() - 1 && C.equals(words.elementAt(i + 1)))) { - sb.append(getLastElement(word).getNewPrefix()); - baseTextIdx += word.length(); - if (it.hasNext()) - ns = it.next(); - else { - sb.append(nodeText.substring(baseTextIdx)); - break; + } + text = value.toString(); + if (parameters.isTrimTextNodes()) { + boolean b = true; + NamedNodeMap attrs = node.getParentNode().getAttributes(); + for (int ai = 0; ai < attrs.getLength(); ai++) { + Node attr = attrs.item(ai); + if (isInExcludeList(attr)) + continue; + if (XML.equals(getNodePrefix(attr)) + && "preserve".equals(attr.getNodeValue()) + && getLocalName(attr).equals("space")) { + b = false; + break; } - } else { - sb.append(word); - baseTextIdx += word.length(); - } } - text = sb.toString(); - } + if (b) { + text = StringUtils.trim(text); + } + } + + Node element = node.getNodeType() == Node.TEXT_NODE ? node.getParentNode() : node; + String nodePrefix = getNodePrefix(element); + String nodeLocalName = getLocalName(element); + String nodeUri = getNamespaceURIByPrefix(nodePrefix); + + String nodeQName = createQName(nodeUri, nodeLocalName); + if (this.qNameAwareElements.contains(nodeQName)) { + text = processQNameText(text); + } + if (this.qNameAwareXPathElements.contains(nodeQName)) { + text = processXPathText(text); + } + outputBuffer.append(text); + } + + private int writeNewXPathCharacter(char ch, int pos) { + pos--; + if (pos < 0) { + char[] newResultArr = new char[tempXpathStorage.length + PREFIX_ARRAY_CAPACITY * 2]; + System.arraycopy(tempXpathStorage, 0, newResultArr, PREFIX_ARRAY_CAPACITY * 2, tempXpathStorage.length); + tempXpathStorage = newResultArr; + pos += PREFIX_ARRAY_CAPACITY * 2; + } + tempXpathStorage[pos] = ch; + return pos; + } + + private int writeXPathPrefix(char ch, int pos) { + pos--; + if (pos < 0) { + char[] newResultArr = new char[tempPrefixStorage.length + PREFIX_ARRAY_CAPACITY]; + System.arraycopy(tempPrefixStorage, 0, newResultArr, PREFIX_ARRAY_CAPACITY, tempPrefixStorage.length); + tempPrefixStorage = newResultArr; + pos += PREFIX_ARRAY_CAPACITY; } - } + tempPrefixStorage[pos] = ch; + return pos; } - outputBuffer.append(text); - } - /** - * Prosessing of process instruction node. - * - * @param node - * process instruction node - */ - protected void processPI(Node node) { - LOGGER.debug("processPI: {}", node); + private String processXPathText(String text) { + + tempXpathStorage = new char[text.length()]; + + int resultPos = tempXpathStorage.length; + + tempPrefixStorage = new char[PREFIX_ARRAY_CAPACITY]; + + int prefixPos = tempPrefixStorage.length; + + XPathParserStates state = COMMON; + + for (int i = text.length() - 1; i >= 0; i--) { + char ch = text.charAt(i); + switch (state) { + case COMMON: + switch (ch) { + case '\'': + state = SINGLE_QUOTED_STRING; + break; + case '"': + state = DOUBLE_QUOTED_STRING; + break; + case ':': + state = COLON; + break; + } + resultPos = writeNewXPathCharacter(ch, resultPos); + break; + + case SINGLE_QUOTED_STRING: + switch (ch) { + case '\'': + state = COMMON; + break; + } + resultPos = writeNewXPathCharacter(ch, resultPos); + break; + + case DOUBLE_QUOTED_STRING: + switch (ch) { + case '"': + state = COMMON; + break; + } + resultPos = writeNewXPathCharacter(ch, resultPos); + break; + + case COLON: + if (ch == ':') { // double colon - axis + state = COMMON; + resultPos = writeNewXPathCharacter(ch, resultPos); + continue; + } + if (isNCSymbol(ch)) { + state = PREFIX; + prefixPos = writeXPathPrefix(ch, prefixPos); + } + break; + case PREFIX: + if (isNCSymbol(ch)) { + prefixPos = writeXPathPrefix(ch, prefixPos); + } else { + String prefix = String.valueOf(tempPrefixStorage, prefixPos, tempPrefixStorage.length - prefixPos); + prefixPos = tempPrefixStorage.length; + String uri = getNamespaceURIByPrefix(prefix); + String newPrefix = getNewPrefix(uri, prefix); + for (int j = newPrefix.length() - 1; j >= 0; j--) { + char newPrefixCh = newPrefix.charAt(j); + resultPos = writeNewXPathCharacter(newPrefixCh, resultPos); + } + switch (ch) { + case '\'': + state = SINGLE_QUOTED_STRING; + break; + case '"': + state = DOUBLE_QUOTED_STRING; + break; + case ':': + state = COLON; + break; + default: + state = COMMON; + } + resultPos = writeNewXPathCharacter(ch, resultPos); + } + break; + + } + } + + String result = String.valueOf(tempXpathStorage, resultPos, tempXpathStorage.length - resultPos); + return result; + } + + /** + * Prosessing of process instruction node. + * + * @param node process instruction node + */ + protected void processPI(Node node) { + /*LOGGER.debug("processPI: {}", node); String nodeName = node.getNodeName(); String nodeValue = node.getNodeValue() != null ? node.getNodeValue() : ""; - StringBuffer output = new StringBuffer(); if (bEnd && getNodeDepth(node) == 1) { - output.append("\n"); + outputBuffer.append("\n"); } - output.append(String.format("", nodeName, + outputBuffer.append(String.format("", nodeName, !nodeValue.isEmpty() ? (" " + nodeValue) : "")); if (bStart && getNodeDepth(node) == 1) { - output.append("\n"); - } - outputBuffer.append(output); - } - - /** - * Prosessing of comment node. - * - * @param node - * comment node - */ - protected void processComment(Node node) { - LOGGER.debug("processComment: {}", node); + outputBuffer.append("\n"); + }*/ + + } + + /** + * Prosessing of comment node. + * + * @param node comment node + */ + protected void processComment(Node node) { + /*LOGGER.debug("processComment: {}", node); if (parameters.isIgnoreComments()) return; - StringBuffer output = new StringBuffer(); if (bEnd && getNodeDepth(node) == 1) { - output.append("\n"); + outputBuffer.append("\n"); } - output.append(String.format("", node.getNodeValue())); + outputBuffer.append(String.format("", node.getNodeValue())); if (bStart && getNodeDepth(node) == 1) { - output.append("\n"); - } - outputBuffer.append(output); - } - - /** - * Prosessing of CDATA node. - * - * @param node - * CDATA node - */ - protected void processCData(Node node) { - LOGGER.debug("processCData:" + node); - outputBuffer.append(processText(node.getNodeValue(), false)); - } - - /** - * Returns an output buffer. - * - * @return Returns an output buffer - */ - protected StringBuffer getOutputBlock() { - return outputBuffer; - } - - /** - * Returns whether a node in the exclusion list. - * - * @param node - * DOM node - * - * @return Returns true if a node there is in exclusion list, false - - * otherwise - */ - protected boolean isInExcludeList(Node node) { - if (excludeList != null - && excludeList.contains(node) - && (node.getNodeType() == Node.ELEMENT_NODE || node instanceof Attr) - && !(node instanceof Attr && (NS.equals(getNodePrefix(node)) || XML - .equals(getNodePrefix(node))))) - return true; - return false; - } - - /** - * Returns a depth of a node in the DOM tree. - * - * @param node - * DOM node - * - * @return Returns a depth - */ - protected int getNodeDepth(Node node) { - int i = -1; - Node prnt = node; - do { - i++; - prnt = prnt.getParentNode(); - } while (prnt != null); - return i; - } - - /** - * Returns whether there is a prefix in the parent output. - * - * @param prfx - * prefix - * - * @return Returns true if a prefix there is in parent output, false - - * otherwise - */ - private boolean outputNSInParent(String prfx) { - for (Entry> en : namespaces.entrySet()) { - if (!bSequential && !prfx.equals(en.getKey())) - continue; - List lst = en.getValue(); - if (lst.size() > 1) { - NamespaceContextParams last = getLastElement(prfx); - for (int i = 2; i <= lst.size(); i++) { - NamespaceContextParams prev = getLastElement(en.getKey(), -i); - if (last.getNewPrefix().equals(prev.getNewPrefix())) { - if (!bSequential && !last.getUri().equals(prev.getUri())) - return false; - else if (prev.isHasOutput() == null || prev.isHasOutput()) - return true; - } - } - } - } - return false; - } - - /** - * Remove unused namespaces from the stack. - * - * @param node - * DOM node - */ - private void removeNamespaces(Node node) { - for (String prefix : namespaces.keySet()) { - List nsLevels = namespaces.get(prefix); - while (!nsLevels.isEmpty() - && getLastElement(prefix).getDepth() >= getNodeDepth(node)) { - nsLevels.remove(nsLevels.size() - 1); - } - } - - Iterator>> it = namespaces - .entrySet().iterator(); - while (it.hasNext()) { - Entry> en = it.next(); - if (en.getValue().size() == 0) - it.remove(); - } - } - - /** - * Prosessing of node attributes. - * - * @param node - * DOM node - * - * @return Returns a list of output attributes - */ - private List processAttributes(final Node node) { - List outAttrsList = new ArrayList(); - - for (int ai = 0; ai < node.getAttributes().getLength(); ai++) { - Node attr = node.getAttributes().item(ai); - if (isInExcludeList(attr)) - continue; - - String prfx = getNodePrefix(attr); - String localName = getLocalName(attr); - if (!NS.equals(prfx) - && !(DEFAULT_NS.equals(prfx) && NS.equals(attr.getNodeName()))) { - Attribute attribute = new Attribute(); - attribute.setPrefix(prfx); - attribute.setLocalName(localName); - attribute.setValue(attr.getNodeValue() != null ? attr.getNodeValue() - : ""); - if (!attribute.getPrefix().isEmpty() - && namespaces.containsKey(attribute.getPrefix())) { - attribute.setNewPrefix(getLastElement(attribute.getPrefix()) - .getNewPrefix()); - } else { - attribute.setNewPrefix(attribute.getPrefix()); + outputBuffer.append("\n"); + } */ + + } + + /** + * Prosessing of CDATA node. + * + * @param node CDATA node + */ + protected void processCData(Node node) { + LOGGER.debug("processCData:" + node); + outputBuffer.append(processText(node.getNodeValue(), false)); + + } + + /** + * Returns an output buffer. + * + * @return Returns an output buffer + */ + protected StringBuilder getOutputBlock() { + return outputBuffer; + } + + /** + * Returns whether a node in the exclusion list. + * + * @param node DOM node + * @return Returns true if a node there is in exclusion list, false - + * otherwise + */ + protected boolean isInExcludeList(Node node) { + if (excludeList != null + && excludeList.contains(node) + && (node.getNodeType() == Node.ELEMENT_NODE || node instanceof Attr) + && !(node instanceof Attr && (XMLNS.equals(getNodePrefix(node)) || XML + .equals(getNodePrefix(node))))) + return true; + return false; + } + + + /** + * Remove unused namespaces from the stack. + * + * @param node DOM node + */ + private void removeNamespaces(Node node) { + + usedPrefixes.deleteLevel(nodeDepth); + declaredPrefixes.deleteLevel(nodeDepth); + } + + /** + * Prosessing of node attributes. + * + * @param node DOM node + * @return Returns a list of output attributes + */ + private void evaluateUriVisibility(final Node node, Set nsDeclarations) { + + String nodePrf = getNodePrefix(node); + String nodeLocalName = getLocalName(node); + String nodeUri = getNamespaceURIByPrefix(nodePrf); + + addNSDeclarationForPrefix(nodePrf, nsDeclarations); + + for (int ai = 0; ai < node.getAttributes().getLength(); ai++) { + Node attr = node.getAttributes().item(ai); + if (isInExcludeList(attr)) continue; + String prfx = getNodePrefix(attr); + if (!XMLNS.equals(prfx)) { + + if (XML.equals(prfx)) { + /** + Canonical XML 2.0 ignores these attributes as well. + */ + continue; + } + + String attrNamespaceURI; + String text = getAttributeValue(attr.getNodeValue()); + //Note: unlike elements, if an attribute doesn't have a prefix, that means it is a locally scoped attribute. + if (EMPTY_PREFIX.equals(prfx)) { + // unqualifierAttr + attrNamespaceURI = nodeUri; + String qName = createQName(attrNamespaceURI, nodeLocalName, getLocalName(attr)); + addVisibilityIfNessesaryByText(qName, text, nsDeclarations, qNameAwareUnqualifiedAttrs); + + } else { + attrNamespaceURI = getNamespaceURIByPrefix(prfx); + // qualifierAttr, check by QualifiedAttr + String qName = createQName(attrNamespaceURI, getLocalName(attr)); + addVisibilityIfNessesaryByText(qName, text, nsDeclarations, qNameAwareQualifiedAttrs); + } + + // addNSDeclarationForPrefix(prfx, nsDeclarations); + if(!prfx.isEmpty()) { + addNSDeclarationForPrefix(prfx, nsDeclarations); + } + + } } - attribute.setValue(processText(attribute.getValue(), true)); - StringBuffer value = new StringBuffer(); - for (int i = 0; i < attribute.getValue().length(); i++) { - char codepoint = attribute.getValue().charAt(i); - if (codepoint == 9 || codepoint == 10 || codepoint == 13) { - value.append(String.format(CF, Integer.toHexString(codepoint) - .toUpperCase())); - } else { - value.append(codepoint); - } - } - attribute.setValue(value.toString()); - - outAttrsList.add(attribute); - } - } - - Collections.sort(outAttrsList, new Comparator() { - public int compare(Attribute x, Attribute y) { - String x_uri, y_uri; - if (XML.equals(x.getPrefix())) { - x_uri = node.lookupNamespaceURI(XML); + String text = node.getTextContent(); + String qName = createQName(nodeUri, nodeLocalName); + addVisibilityIfNessesaryByText(qName, text, nsDeclarations, qNameAwareElements); + addXPathVisibilityIfNessesaryByText(qName, text, nsDeclarations); + + } + + private boolean isNCSymbol(char ch) { + return Character.isLetterOrDigit(ch) || ch == '_' || ch == '-' || ch == '.'; + } + + private void addXPathVisibilityIfNessesaryByText(String qName, String text, Set nsDeclarations) { + if (qNameAwareXPathElements.contains(qName)) { + // Search for single colons : in the XPath expression, but do not consider single colons inside quoted strings. + // Double colons are used for axes, e.g. in self::node() , "self:" is not a prefix, but an axis name. + // The prefix will be present just before the single colon. Go backwards from the colon, skip whitespace, and + // extract the prefix, by collecting characters till the first non NCName match. e.g. in /soap : Body, extract the "soap". + // The NCName production is defined in [XML-NAMES]. + + Set xPathPrefixes = new HashSet(); + + XPathParserStates state = COMMON; + + char[] prefixArr = new char[PREFIX_ARRAY_CAPACITY]; + int pos = prefixArr.length; + + for (int i = text.length() - 1; i >= 0; i--) { + char ch = text.charAt(i); + switch (state) { + case COMMON: + if (ch == '\'') { + state = SINGLE_QUOTED_STRING; + continue; + } + if (ch == '"') { + state = DOUBLE_QUOTED_STRING; + continue; + } + if (ch == ':') { + state = COLON; + continue; + } + break; + case SINGLE_QUOTED_STRING: + if (ch == '\'') { + state = COMMON; + } + break; + case DOUBLE_QUOTED_STRING: + if (ch == '"') { + state = COMMON; + } + break; + case COLON: + if (ch == ':') { // double colon - axis + state = COMMON; + continue; + } + if (isNCSymbol(ch)) { + state = PREFIX; + pos--; + if (pos < 0) { + char[] newPrefixArr = new char[prefixArr.length + PREFIX_ARRAY_CAPACITY]; + System.arraycopy(prefixArr, 0, newPrefixArr, PREFIX_ARRAY_CAPACITY, prefixArr.length); + prefixArr = newPrefixArr; + pos += PREFIX_ARRAY_CAPACITY; + } + prefixArr[pos] = ch; + } + break; + case PREFIX: + if (isNCSymbol(ch)) { + pos--; + if (pos < 0) { + char[] newPrefixArr = new char[prefixArr.length + PREFIX_ARRAY_CAPACITY]; + System.arraycopy(prefixArr, 0, newPrefixArr, PREFIX_ARRAY_CAPACITY, prefixArr.length); + prefixArr = newPrefixArr; + pos += PREFIX_ARRAY_CAPACITY; + } + prefixArr[pos] = ch; + } else { + String prefix = String.valueOf(prefixArr, pos, prefixArr.length - pos); + pos = prefixArr.length; + xPathPrefixes.add(prefix); + if (ch == '\'') { + state = SINGLE_QUOTED_STRING; + continue; + } + if (ch == '"') { + state = DOUBLE_QUOTED_STRING; + continue; + } + if (ch == ':') { + state = COLON; + continue; + } + state = COMMON; + } + break; + + } + } + + for (String prefix : xPathPrefixes) { + addNSDeclarationForPrefix(prefix, nsDeclarations); + } + + } + } + + private void addNSDeclarationForPrefix(String prefix, Set nsDeclarations) { + + String prefixUri = getNamespaceURIByPrefix(prefix); + if (bSequential) { + // firstKey - url + // secondKey - prefix + if (usedPrefixes.getByFirstKey(prefixUri) == null) { + NSDeclaration nsDeclaration = new NSDeclaration(); + nsDeclaration.setUri(prefixUri); + nsDeclarations.add(nsDeclaration); + } } else { - NamespaceContextParams x_stack = getLastElement(x.getPrefix()); - x_uri = x_stack != null ? x_stack.getUri() : ""; + // firstKey - prefix + // secondKey - url + String existsUri = usedPrefixes.getByFirstKey(prefix); + + // hack xmlns="" + if (existsUri == null && EMPTY_PREFIX.equals(prefix) && EMPTY_URI.equals(prefixUri)) { + usedPrefixes.definePrefix(prefix, prefixUri, nodeDepth); + return; + } + + if (existsUri == null || !existsUri.equals(prefixUri)) { + usedPrefixes.definePrefix(prefix, prefixUri, nodeDepth); + NSDeclaration nsDeclaration = new NSDeclaration(); + nsDeclaration.setUri(prefixUri); + nsDeclaration.setPrefix(prefix); + nsDeclarations.add(nsDeclaration); + } + + } + } + + + private void addVisibilityIfNessesaryByText(String checkStr, String text, Set nsDeclarations, Set checkSet) { + if (checkSet.contains(checkStr)) { + String prefix = getTextPrefix(text); + if (XML.equals(prefix)) { // Canonical XML 2.0 should ignore xml declaration. + return; + } + addNSDeclarationForPrefix(prefix, nsDeclarations); } - if (XML.equals(y.getPrefix())) { - y_uri = node.lookupNamespaceURI(XML); + + } + + private String getTextPrefix(String text) { + int idx = text.indexOf(C); + String prefix = ""; + if (idx > -1) { + prefix = StringUtils.substring(text, 0, idx); + } + return prefix; + } + + + /** + * Add namespaces to stack. + * + * @param node DOM node + */ + private void addNamespaces(Node node) { + + for (int ni = 0; ni < node.getAttributes().getLength(); ni++) { + Node attr = node.getAttributes().item(ni); + if (isInExcludeList(attr)) + continue; + String suffix = getLocalName(attr); + String prfxNs = getNodePrefix(attr); + + if (XMLNS.equals(prfxNs)) { + String uri = attr.getNodeValue(); + declaredPrefixes.definePrefix(suffix, uri, nodeDepth); + } + } + + // happens: + String prfxEl = getNodePrefix(node); + String uri = node.getNamespaceURI(); + if (prfxEl.equals("") && uri!=null && !uri.equals("")){ + declaredPrefixes.definePrefix(prfxEl,uri,nodeDepth); + } + } + + + /** + * Replace special characters. + * + * @param text input text + * @param bAttr true if text is attribute value + * @return replacement text + */ + private String processText(String text, boolean bAttr) { + + text = StringUtils.replace(text, "&", "&"); + text = StringUtils.replace(text, "<", "<"); + if (!bAttr) { + text = StringUtils.replace(text, ">", ">"); } else { - NamespaceContextParams y_stack = getLastElement(y.getPrefix()); - y_uri = y_stack != null ? y_stack.getUri() : ""; - } - return String.format("%s:%s", x_uri, x.getLocalName()).compareTo( - String.format("%s:%s", y_uri, y.getLocalName())); - } - }); - - return outAttrsList; - } - - /** - * Prosessing of namespace attributes. - * - * @param node - * DOM node - * - * @return Returns a list of output namespace attributes - */ - private List processNamespaces(Node node) { - addNamespaces(node); - - List outNSList = new ArrayList(); - - int depth = getNodeDepth(node); - for (String prefix : namespaces.keySet()) { - NamespaceContextParams ncp = getLastElement(prefix); - if (ncp.getDepth() != depth) { - NamespaceContextParams entry = ncp.clone(); - if (entry.isHasOutput() != null && depth > 0) - entry.setHasOutput(false); - entry.setDepth(depth); - namespaces.get(prefix).add(entry); - ncp = entry; - } - if (ncp.isHasOutput() != null && !ncp.isHasOutput()) { - if (isPrefixVisible(node, prefix)) { - NamespaceContextParams entry = ncp.clone(); - entry.setPrefix(prefix); - outNSList.add(entry); - } else - continue; - ncp.setHasOutput(true); - } - } - - if (bSequential) { - Collections.sort(outNSList, new Comparator() { - public int compare(NamespaceContextParams x, NamespaceContextParams y) { - return x.getUri().compareTo(y.getUri()); - } - }); - - for (NamespaceContextParams entry : outNSList) { - NamespaceContextParams ncp = getLastElement(entry.getPrefix()); - if (!sequentialUriMap.containsKey(entry.getUri())) - sequentialUriMap.put(entry.getUri(), - String.format("n%s", sequentialUriMap.size())); - entry.setNewPrefix(sequentialUriMap.get(entry.getUri())); - ncp.setNewPrefix(entry.getNewPrefix()); - } - } else { - Collections.sort(outNSList, new Comparator() { - public int compare(NamespaceContextParams x, NamespaceContextParams y) { - return x.getPrefix().compareTo(y.getPrefix()); - } - }); - } - return outNSList; - } - - /** - * Add namespaces to stack. - * - * @param node - * DOM node - */ - private void addNamespaces(Node node) { - for (int ni = 0; ni < node.getAttributes().getLength(); ni++) { - Node attr = node.getAttributes().item(ni); - if (isInExcludeList(attr)) - continue; - String prefix = getLocalName(attr); - - String prfxNs = getNodePrefix(attr); - - if (NS.equals(prfxNs) || (DEFAULT_NS.equals(prfxNs) && NS.equals(prefix))) { - if (NS.equals(prefix)) { - prefix = ""; - } - - String uri = attr.getNodeValue(); - - List stack = namespaces.get(prefix); - if (stack != null && uri.equals(getLastElement(prefix).getUri())) - continue; - - if (!namespaces.containsKey((prefix))) { - namespaces.put(prefix, new ArrayList()); - } - NamespaceContextParams nsp = new NamespaceContextParams(uri, false, - prefix, getNodeDepth(node)); - if (namespaces.get(prefix).size() == 0 - || getNodeDepth(node) != getLastElement(prefix).getDepth()) - namespaces.get(prefix).add(nsp); - else - namespaces.get(prefix).set(namespaces.get(prefix).size() - 1, nsp); - } - } - } - - /** - * Returns whether to show the prefix in the output of the node. - * - * @param node - * DOM node - * @param prefix - * prefix - * - * @return Returns true if prefix is shown in the output of the node, false - - * otherwise. - */ - private boolean isPrefixVisible(Node node, String prefix) { - String nodePrefix = getNodePrefix(node); - if (nodePrefix.equals(prefix)) { - return true; - } - - String nodeLocalName = getLocalName(node); - if (parameters.getQnameAwareElements().size() > 0) { - NamespaceContextParams ncp = getLastElement(prefix); - String prfx = ncp.getPrefix(); - String childText = node.getTextContent(); - if (childText != null && childText.startsWith(prfx + C) - && node.getChildNodes().getLength() == 1) { - NamespaceContextParams attrPrfxNcp = getLastElement(nodePrefix); - for (QNameAwareParameter en : parameters.getQnameAwareElements()) { - if (nodeLocalName.equals(en.getName()) - && en.getNs().equals(attrPrfxNcp.getUri())) { - return true; - } - } - } - } - if (parameters.getQnameAwareXPathElements().size() > 0 - && node.getChildNodes().getLength() == 1) { - NamespaceContextParams ncp = getLastElement(nodePrefix); - String childText = node.getTextContent(); - for (QNameAwareParameter en : parameters.getQnameAwareXPathElements()) { - if (nodeLocalName.equals(en.getName()) - && ncp.getUri().equals(en.getNs())) { - NSContext nsContext = xpathesNsMap.get(childText); - try { - if (nsContext == null) { - nsContext = new NSContext(); - XPathParser xpathParser = new XPathParser(null, null); - org.apache.xpath.compiler.Compiler xpathCompiler = new org.apache.xpath.compiler.Compiler(); - xpathParser.initXPath(xpathCompiler, childText, nsContext); - xpathesNsMap.put(childText, nsContext); - nsContext.setWords(xpathCompiler.getTokenQueue()); + text = StringUtils.replace(text, "\"", """); + text = StringUtils.replace(text, "#xA", " "); + text = StringUtils.replace(text, "#x9", " "); + } + text = StringUtils.replace(text, "#xD", " "); + return text; + } + + /** + * Returns the node local name. + * + * @param node DOM node + * @return Returns local name + */ + private String getLocalName(Node node) { + String name = node.getLocalName()!=null?node.getLocalName():node.getNodeName(); + if (XMLNS.equals(name)) { + return ""; // to simplify code + } + int idx = name.indexOf(C); + if (idx > -1) + return name.substring(idx + 1); + return name; + } + + /** + * Returns the node prefix. + * + * @param node DOM node + * @return Returns prefix + */ + private String getNodePrefix(Node node) { + String prfx = node.getPrefix(); + if (prfx == null || prfx.isEmpty()) { + prfx = ""; + String name = node.getNodeName(); + if (XMLNS.equals(name)) { + return name; // to simplify code } - if (nsContext.getXpathNs().contains(prefix)) - return true; - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - } - } - } - } - - NamespaceContextParams ncp = getLastElement(prefix); - String prfx = ncp.getPrefix(); - for (int ai = 0; ai < node.getAttributes().getLength(); ai++) { - Node attr = node.getAttributes().item(ai); - String attrPrfx = getNodePrefix(attr); - if (!attrPrfx.isEmpty() && attrPrfx.equals(prefix)) { - return true; - } - if (parameters.getQnameAwareAttributes().size() > 0) { - String attrValue = attr.getNodeValue(); - if (attrValue.startsWith(prfx + C)) { - String attrLocalName = getLocalName(attr); - String attrPrefix = getNodePrefix(attr); - NamespaceContextParams attrPrfxNcp = getLastElement(attrPrefix); - for (QNameAwareParameter en : parameters.getQnameAwareAttributes()) { - if (attrLocalName.equals(en.getName()) - && en.getNs().equals(attrPrfxNcp.getUri())) { - return true; + int idx = name.indexOf(C); + if (idx > -1) + return StringUtils.substring(name, 0, idx); + } + return prfx; + } + + + /** + * primer: canonicalization of element ds:SignedInfo required namespace difinition xmlns:ds="http://www.w3.org/2000/09/xmldsig#" + * in the parent node ds:Signature. + * Load all namespace definitions for canonicalized element before canonicalization process start. + */ + + protected void loadParentNamespaces(Node node) { + Node current = node; + // processing up to root + + + List parentNodeList = new LinkedList(); + while ((current = current.getParentNode()) != null && (current.getNodeType() != Node.DOCUMENT_NODE)) { + // revert list + parentNodeList.add(current); + } + + int depth = 0; + for (int i = parentNodeList.size()-1;i>=0;i--) { + depth++; + Node pnode = parentNodeList.get(i); + for (int ni = 0; ni < pnode.getAttributes().getLength(); ni++) { + Node attr = pnode.getAttributes().item(ni); + String suffix = getLocalName(attr); + String prfxNs = getNodePrefix(attr); + + if (XMLNS.equals(prfxNs)) { + String uri = attr.getNodeValue(); + this.declaredPrefixes.definePrefix(suffix, uri, -depth); + } + } - } - } - } - } - - return false; - } - - /** - * Replace special characters. - * - * @param text - * input text - * @param bAttr - * true if text is attribute value - * - * @return replacement text - */ - private String processText(String text, boolean bAttr) { - text = text.replace("&", "&"); - text = text.replace("<", "<"); - if (!bAttr) { - text = text.replace(">", ">"); - } else { - text = text.replace("\"", """); - text = text.replace("#xA", " "); - text = text.replace("#x9", " "); - } - text = text.replace("#xD", " "); - return text; - } - - /** - * Returns the node local name. - * - * @param node - * DOM node - * @return Returns local name - */ - private String getLocalName(Node node) { - if (node.getLocalName() != null) - return node.getLocalName(); - String name = node.getNodeName(); - int idx = name.indexOf(C); - if (idx > -1) - return name.substring(idx + 1); - return name; - } - - /** - * Returns parameter by key. - * - * @param key - * key - * @return parameter - */ - private NamespaceContextParams getLastElement(String key) { - return getLastElement(key, -1); - } - - /** - * Returns parameter by key. - * - * @param key - * key - * @param shift - * shift - * @return parameter - */ - private NamespaceContextParams getLastElement(String key, int shift) { - List lst = namespaces.get(key); - return lst.size() + shift > -1 ? lst.get(lst.size() + shift) : null; - } - - /** - * Returns the node prefix. - * - * @param node - * DOM node - * @return Returns prefix - */ - private String getNodePrefix(Node node) { - String prfx = node.getPrefix(); - if (prfx == null || prfx.isEmpty()) { - prfx = ""; - String name = node.getNodeName(); - int idx = name.indexOf(C); - if (idx > -1) - return name.substring(0, idx); - } - return prfx; - } + + } + depth++; + // HACK but node.name=SOAP-ENV:Body ??? + this.declaredPrefixes.definePrefix("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", -depth); + + } + + + } \ No newline at end of file diff --git a/src/main/java/ru/relex/c14n2/NSContext.java b/src/main/java/ru/relex/c14n2/NSContext.java deleted file mode 100644 index 8b3fe60..0000000 --- a/src/main/java/ru/relex/c14n2/NSContext.java +++ /dev/null @@ -1,80 +0,0 @@ -package ru.relex.c14n2; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.xml.utils.ObjectVector; -import org.apache.xml.utils.PrefixResolver; -import org.w3c.dom.Node; - -/** - * The internal representation of the XPath declaration. - */ -class NSContext implements PrefixResolver { - - private List xpathNs; - private ObjectVector words; - - /** - * Constructor. - */ - public NSContext() { - xpathNs = new ArrayList(); - } - - /** - * Returns a list of namespace prefixes from the XPath declaration. - * - * @return Returns a list - */ - public List getXpathNs() { - return xpathNs; - } - - /** - * Returns the lexical elements of the XPath declaration. - * - * @return Returns the lexical elements - */ - public ObjectVector getWords() { - return words; - } - - public void setWords(ObjectVector words) { - this.words = words; - } - - /** - * {@inheritDoc} - */ - @Override - public String getBaseIdentifier() { - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public String getNamespaceForPrefix(String prefix, Node node) { - xpathNs.add(prefix); - return prefix; - } - - /** - * {@inheritDoc} - */ - @Override - public String getNamespaceForPrefix(String prefix) { - xpathNs.add(prefix); - return prefix; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean handlesNullPrefixes() { - return false; - } -} \ No newline at end of file diff --git a/src/main/java/ru/relex/c14n2/NamespaceContextParams.java b/src/main/java/ru/relex/c14n2/NamespaceContextParams.java deleted file mode 100644 index f231b79..0000000 --- a/src/main/java/ru/relex/c14n2/NamespaceContextParams.java +++ /dev/null @@ -1,119 +0,0 @@ -package ru.relex.c14n2; - -/** - * The internal representation of the namespace declaration (xmlns attribure). - */ -class NamespaceContextParams { - private String uri = ""; - private String prefix = ""; - private int depth = 1; - private String newPrefix = ""; - private Boolean hasOutput = null; - - /** - * Constructor. - * - * @param uri - * URI - * @param hasOutput - * output flag - * @param newPrefix - * new local name - * @param depth - * depth of the node - */ - public NamespaceContextParams(String uri, boolean hasOutput, - String newPrefix, int depth) { - setUri(uri); - setHasOutput(hasOutput); - setNewPrefix(newPrefix); - setPrefix(newPrefix); - setDepth(depth); - } - - /** - * Constructor. - */ - public NamespaceContextParams() { - } - - /** - * Returns the URI of this attribute. - * - * @return Returns the URI - */ - public String getUri() { - return uri; - } - - public void setUri(String uri) { - this.uri = uri; - } - - /** - * Returns whether this declaration in the output. - * - * @return Returns true if this declaration is used in output, false - * otherwise. - */ - public Boolean isHasOutput() { - return hasOutput; - } - - public void setHasOutput(Boolean hasOutput) { - this.hasOutput = hasOutput; - } - - /** - * Returns the new local name (in "Prefix rewrite" mode) of the qualified name - * of this attribute. - * - * @return Returns the new local name - */ - public String getNewPrefix() { - return newPrefix; - } - - public void setNewPrefix(String newPrefix) { - this.newPrefix = newPrefix; - } - - /** - * Returns the depth of the parent node in the DOM tree. - * - * @return Returns the depth - */ - public int getDepth() { - return depth; - } - - public void setDepth(int depth) { - this.depth = depth; - } - - /** - * Returns the local name of the qualified name of this attribute. - * - * @return Returns the prefix - */ - public String getPrefix() { - return prefix; - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } - - /** - * {@inheritDoc} - */ - public NamespaceContextParams clone() { - NamespaceContextParams ncp = new NamespaceContextParams(); - ncp.depth = depth; - ncp.hasOutput = hasOutput; - ncp.newPrefix = newPrefix; - ncp.prefix = prefix; - ncp.uri = uri; - return ncp; - } -} \ No newline at end of file diff --git a/src/main/java/ru/relex/c14n2/util/Attribute.java b/src/main/java/ru/relex/c14n2/util/Attribute.java new file mode 100644 index 0000000..be34ae9 --- /dev/null +++ b/src/main/java/ru/relex/c14n2/util/Attribute.java @@ -0,0 +1,78 @@ +package ru.relex.c14n2.util; + +/** + * The internal representation of the attribute. + */ +public class Attribute { + private String uri; + private String localName; + private String value; + private boolean attributeQualified=true; + private String attrPrfx; + + public String getOldPrefix() { + return oldPrefix; + } + + private String oldPrefix; + + /** + * Returns the uri of the qualified name of this attribute. + * + * @return Returns the uri + */ + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + + /** + * Returns the local part of the qualified name of this attribute. + * + * @return Returns the local name + */ + public String getLocalName() { + return localName; + } + + public void setLocalName(String localName) { + this.localName = localName; + } + + /** + * Returns the value of this attribute. + * + * @return Returns the value + */ + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public void setAttributeQualified(boolean attributeQualified) { + this.attributeQualified = attributeQualified; + } + + public boolean isAttributeQualified() { + return attributeQualified; + } + + public void setOldPrefix(String oldPrefix) { + this.oldPrefix = oldPrefix; + } + + public String getAttrPrfx() { + return attrPrfx; + } + + public void setAttrPrfx(String attrPrfx) { + this.attrPrfx = attrPrfx; + } +} \ No newline at end of file diff --git a/src/main/java/ru/relex/c14n2/util/NSDeclaration.java b/src/main/java/ru/relex/c14n2/util/NSDeclaration.java new file mode 100644 index 0000000..498fe3b --- /dev/null +++ b/src/main/java/ru/relex/c14n2/util/NSDeclaration.java @@ -0,0 +1,45 @@ +package ru.relex.c14n2.util; + +/** + * + */ +public class NSDeclaration { + private String uri; + private String prefix; + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + NSDeclaration that = (NSDeclaration) o; + + if (uri != null ? !uri.equals(that.uri) : that.uri != null) return false; + return prefix != null ? prefix.equals(that.prefix) : that.prefix == null; + + } + + @Override + public int hashCode() { + int result = uri != null ? uri.hashCode() : 0; + result = 31 * result + (prefix != null ? prefix.hashCode() : 0); + return result; + } + +} diff --git a/src/main/java/ru/relex/c14n2/Parameters.java b/src/main/java/ru/relex/c14n2/util/Parameters.java similarity index 54% rename from src/main/java/ru/relex/c14n2/Parameters.java rename to src/main/java/ru/relex/c14n2/util/Parameters.java index 685cfb3..794b1d5 100644 --- a/src/main/java/ru/relex/c14n2/Parameters.java +++ b/src/main/java/ru/relex/c14n2/util/Parameters.java @@ -1,4 +1,4 @@ -package ru.relex.c14n2; +package ru.relex.c14n2.util; import java.util.ArrayList; import java.util.List; @@ -13,9 +13,11 @@ public class Parameters { private boolean ignoreComments = true; private boolean trimTextNodes = false; private String prefixRewrite = NONE; - private List QnameAwareAttributes = new ArrayList(); - private List QnameAwareElements = new ArrayList(); - private List QnameAwareXPathElements = new ArrayList(); + private List qnameAwareQualifiedAttributes = new ArrayList(); + private List qnameAwareUnqualifiedAttributes = new ArrayList(); + private List qnameAwareElements = new ArrayList(); + private List qnameAwareXPathElements = new ArrayList(); + /** * Returns whether to ignore comments during canonicalization. @@ -59,50 +61,35 @@ public void setPrefixRewrite(String prefixRewrite) { this.prefixRewrite = prefixRewrite; } - /** - * Returns a list of parameters which defines the qualified attribute names - * and unqualified attribute names whose entire content must be processed as - * QName-valued for the purposes of canonicalization. - * - * @return Returns a list - */ - public List getQnameAwareAttributes() { - return QnameAwareAttributes; + public List getQnameAwareQualifiedAttributes() { + return qnameAwareQualifiedAttributes; } - public void setQnameAwareAttributes( - List qnameAwareAttributes) { - QnameAwareAttributes = qnameAwareAttributes; + public void setQnameAwareQualifiedAttributes(List qnameAwareQualifiedAttributes) { + this.qnameAwareQualifiedAttributes = qnameAwareQualifiedAttributes; + } + + public List getQnameAwareUnqualifiedAttributes() { + return qnameAwareUnqualifiedAttributes; + } + + public void setQnameAwareUnqualifiedAttributes(List qnameAwareUnqualifiedAttributes) { + this.qnameAwareUnqualifiedAttributes = qnameAwareUnqualifiedAttributes; } - /** - * Returns a list of parameters which defines the qualified element names - * whose entire content must be processed as QName-valued for the purposes of - * canonicalization. - * - * @return Returns a list - */ public List getQnameAwareElements() { - return QnameAwareElements; + return qnameAwareElements; } public void setQnameAwareElements(List qnameAwareElements) { - QnameAwareElements = qnameAwareElements; + this.qnameAwareElements = qnameAwareElements; } - /** - * Returns a list of parameters which defines the element names that contain - * XPath 1.0 expressions whose entire content must be processed as - * QName-valued for the purposes of canonicalization. - * - * @return Returns a list - */ public List getQnameAwareXPathElements() { - return QnameAwareXPathElements; + return qnameAwareXPathElements; } - public void setQnameAwareXPathElements( - List qnameAwareXPathElements) { - QnameAwareXPathElements = qnameAwareXPathElements; + public void setQnameAwareXPathElements(List qnameAwareXPathElements) { + this.qnameAwareXPathElements = qnameAwareXPathElements; } } \ No newline at end of file diff --git a/src/main/java/ru/relex/c14n2/util/PrefixesContainer.java b/src/main/java/ru/relex/c14n2/util/PrefixesContainer.java new file mode 100644 index 0000000..b4cbe0c --- /dev/null +++ b/src/main/java/ru/relex/c14n2/util/PrefixesContainer.java @@ -0,0 +1,73 @@ +package ru.relex.c14n2.util; + +import java.util.*; + +/** + * Class contains function for search support of exists node prefixes declaratoins + * firstKey - prefix in the original document + * secondKey - namespace uri + * level - element depth in the document tree + */ +public class PrefixesContainer { + + + private Map> prefixMap; + + private Map> prefDefLevel; + + public PrefixesContainer() { + prefixMap = new HashMap>(); + prefDefLevel = new HashMap>(); + } + + /** + * xmlns:firstKey="URI" + * @param firstKey + * @param secondKey + * @param level + */ + public void definePrefix(String firstKey, String secondKey, Integer level) { + + if (!prefixMap.containsKey(firstKey)){ + prefixMap.put(firstKey,new LinkedList()); + } + + if (!prefDefLevel.containsKey(level)){ + prefDefLevel.put(level, new LinkedList()); + } + + prefixMap.get(firstKey).push(secondKey); + prefDefLevel.get(level).push(firstKey); + } + + + /** + * search prefix declaration from the level and below + * @param firstKey + * @return + */ + public String getByFirstKey(String firstKey) { + LinkedList list = prefixMap.get(firstKey); + if (list==null || list.isEmpty()) { + return null; + } + return list.peek(); + } + + + /** + * delete prefix information defined at level. + * (while processing element end) + * @param level + */ + public void deleteLevel(Integer level) { + LinkedList list = prefDefLevel.get(level); + if (list!=null) { + for (String firstKey : list) { + prefixMap.get(firstKey).pop(); + } + list.clear(); + } + } + +} diff --git a/src/main/java/ru/relex/c14n2/QNameAwareParameter.java b/src/main/java/ru/relex/c14n2/util/QNameAwareParameter.java similarity index 70% rename from src/main/java/ru/relex/c14n2/QNameAwareParameter.java rename to src/main/java/ru/relex/c14n2/util/QNameAwareParameter.java index 497c29f..2a997fc 100644 --- a/src/main/java/ru/relex/c14n2/QNameAwareParameter.java +++ b/src/main/java/ru/relex/c14n2/util/QNameAwareParameter.java @@ -1,4 +1,4 @@ -package ru.relex.c14n2; +package ru.relex.c14n2.util; /** * The internal representation of qualified element names, element names that @@ -8,6 +8,7 @@ public class QNameAwareParameter { private String name; private String ns; + private String parentName; /** * Constructor. @@ -22,6 +23,13 @@ public QNameAwareParameter(String name, String ns) { this.ns = ns; } + + public QNameAwareParameter(String parentName, String parentNs, String name) { + this.parentName=parentName; + this.ns = parentNs; + this.name = name; + } + /** * Returns a name of element, attribute, etc. * @@ -47,4 +55,12 @@ public String getNs() { public void setNs(String ns) { this.ns = ns; } + + public String getParentName() { + return parentName; + } + + public void setParentName(String parentName) { + this.parentName = parentName; + } } \ No newline at end of file diff --git a/src/main/java/ru/relex/c14n2/util/XPathParserStates.java b/src/main/java/ru/relex/c14n2/util/XPathParserStates.java new file mode 100644 index 0000000..f3f12ff --- /dev/null +++ b/src/main/java/ru/relex/c14n2/util/XPathParserStates.java @@ -0,0 +1,7 @@ +package ru.relex.c14n2.util; + +/** + */ +public enum XPathParserStates { + COMMON, SINGLE_QUOTED_STRING, DOUBLE_QUOTED_STRING, COLON, PREFIX +} diff --git a/src/test/java/ru/relex/c14n2/CanonicalizerTest.java b/src/test/java/ru/relex/c14n2/CanonicalizerTest.java index 374c54b..0286e8d 100644 --- a/src/test/java/ru/relex/c14n2/CanonicalizerTest.java +++ b/src/test/java/ru/relex/c14n2/CanonicalizerTest.java @@ -1,528 +1,539 @@ package ru.relex.c14n2; -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.util.ArrayList; -import java.util.List; +import org.apache.xml.serializer.utils.DOM2Helper; +import org.testng.Assert; +import org.testng.annotations.Test; +import org.w3c.dom.*; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import ru.relex.c14n2.util.Parameters; +import ru.relex.c14n2.util.QNameAwareParameter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; - -import org.testng.Assert; -import org.testng.annotations.Test; -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; +import java.io.*; +import java.util.ArrayList; +import java.util.List; public class CanonicalizerTest { - @Test(threadPoolSize = 10, invocationCount = 1000, invocationTimeOut = 0) - public void testMultiThread() { - testN1Default(); - testN1Comment(); - testN2Default(); - testN2Trim(); - testN3Default(); - testN3Prefix(); - testN3Trim(); - testN4Default(); - testN4Trim(); - testN5Default(); - testN5Trim(); - testN6Default(); - testNsPushdownDefault(); - testNsPushdownPrefix(); - testNsDefaultDefault(); - testNsDefaultPrefix(); - testNsSortDefault(); - testNsSortPrefix(); - testNsRedeclDefault(); - testNsRedeclPrefix(); - testNsSuperfluousDefault(); - testNsSuperfluousPrefix(); - testNsXmlDefault(); - testNsXmlPrefix(); - testNsXmlQname(); - testNsXmlPrefixQname(); - testNsContentDefault(); - testNsContentQnameElem(); - testNsContentQnameXpathElem(); - testNsContentPrefixQnameXPathElem(); - } - - @Test - public void testN1Default() { - Assert.assertTrue(processTest("1", "inC14N1", "c14nDefault")); - } - - @Test - public void testN1Comment() { - Assert.assertTrue(processTest("2", "inC14N1", "c14nComment")); - } - - @Test - public void testN2Default() { - Assert.assertTrue(processTest("3", "inC14N2", "c14nDefault")); - } - - @Test - public void testN2Trim() { - Assert.assertTrue(processTest("4", "inC14N2", "c14nTrim")); - } - - @Test - public void testN21Default() { - Assert.assertTrue(processTest("1r", "inC14N2_1", "c14nDefault")); - } - - @Test - public void testN21Trim() { - Assert.assertTrue(processTest("2r", "inC14N2_1", "c14nTrim")); - } - - @Test - public void testN3Default() { - Assert.assertTrue(processTest("5", "inC14N3", "c14nDefault")); - } - - @Test - public void testN3Prefix() { - Assert.assertTrue(processTest("6", "inC14N3", "c14nPrefix")); - } - - @Test - public void testN3Trim() { - Assert.assertTrue(processTest("7", "inC14N3", "c14nTrim")); - } - - @Test - public void testN4Default() { - Assert.assertTrue(processTest("8", "inC14N4", "c14nDefault")); - } - - @Test - public void testN4Trim() { - Assert.assertTrue(processTest("9", "inC14N4", "c14nTrim")); - } - - @Test - public void testN5Default() { - Assert.assertTrue(processTest("10", "inC14N5", "c14nDefault")); - } - - @Test - public void testN5Trim() { - Assert.assertTrue(processTest("11", "inC14N5", "c14nTrim")); - } - - @Test - public void testN6Default() { - Assert.assertTrue(processTest("12", "inC14N6", "c14nDefault")); - } - - @Test - public void testNsPushdownDefault() { - Assert.assertTrue(processTest("13", "inNsPushdown", "c14nDefault")); - } - - @Test - public void testNsPushdownPrefix() { - Assert.assertTrue(processTest("14", "inNsPushdown", "c14nPrefix")); - } - - @Test - public void testNsDefaultDefault() { - Assert.assertTrue(processTest("15", "inNsDefault", "c14nDefault")); - } - - @Test - public void testNsDefaultPrefix() { - Assert.assertTrue(processTest("16", "inNsDefault", "c14nPrefix")); - } - - @Test - public void testNsSortDefault() { - Assert.assertTrue(processTest("17", "inNsSort", "c14nDefault")); - } - - @Test - public void testNsSortPrefix() { - Assert.assertTrue(processTest("18", "inNsSort", "c14nPrefix")); - } - - @Test - public void testNsRedeclDefault() { - Assert.assertTrue(processTest("19", "inNsRedecl", "c14nDefault")); - } - - @Test - public void testNsRedeclPrefix() { - Assert.assertTrue(processTest("20", "inNsRedecl", "c14nPrefix")); - } - - @Test - public void testNsSuperfluousDefault() { - Assert.assertTrue(processTest("21", "inNsSuperfluous", "c14nDefault")); - } - - @Test - public void testNsSuperfluousPrefix() { - Assert.assertTrue(processTest("22", "inNsSuperfluous", "c14nPrefix")); - } - - @Test - public void testNsXmlDefault() { - Assert.assertTrue(processTest("23", "inNsXml", "c14nDefault")); - } - - @Test - public void testNsXmlPrefix() { - Assert.assertTrue(processTest("24", "inNsXml", "c14nPrefix")); - } - - @Test - public void testNsXmlQname() { - Assert.assertTrue(processTest("25", "inNsXml", "c14nQname")); - } - - @Test - public void testNsXmlPrefixQname() { - Assert.assertTrue(processTest("26", "inNsXml", "c14nPrefixQname")); - } - - @Test - public void testNsContentDefault() { - Assert.assertTrue(processTest("27", "inNsContent", "c14nDefault")); - } - - @Test - public void testNsContentQnameElem() { - Assert.assertTrue(processTest("28", "inNsContent", "c14nQnameElem")); - } - - @Test - public void testNsContentQnameXpathElem() { - Assert.assertTrue(processTest("29", "inNsContent", "c14nQnameXpathElem")); - } - - @Test - public void testNsContentPrefixQnameXPathElem() { - Assert.assertTrue(processTest("30", "inNsContent", - "c14nPrefixQnameXpathElem")); - } - - @Test - public void testRC242Default() { - Assert.assertTrue(processTest("3r", "inRC2_4_2", "c14nDefault")); - } - - @Test - public void testN22Trim() { - Assert.assertTrue(processTest("4r", "inC14N2_2", "c14nTrim")); - } - - @Test - public void testN22TrimExcl1() { - Assert.assertTrue(processTest("5r", "inC14N2_2", "c14nTrim", - new ICanonicalizerExcludeList() { - - @Override - public String getExcludeListName() { - return "excl1"; - } - - @Override - public List getExcludeList(Document doc) { - NodeList nl = doc.getChildNodes(); - List nodes = new ArrayList(); - nodes.add(nl.item(0).getChildNodes().item(3)); - return nodes; - } - })); - } - - @Test - public void testN3DefaultExcl1() { - Assert.assertTrue(processTest("6r", "inC14N3", "c14nDefault", - new ICanonicalizerExcludeList() { - - @Override - public String getExcludeListName() { - return "excl1"; - } - - @Override - public List getExcludeList(Document doc) { - NodeList nl = doc.getChildNodes(); - List nodes = new ArrayList(); - NamedNodeMap e5Attrs = nl.item(1).getChildNodes().item(9) - .getAttributes(); - String[] names = new String[] { "a:attr", "attr" }; - for (String name : names) { - nodes.add(e5Attrs.getNamedItem(name)); + @Test(threadPoolSize = 10, invocationCount = 1000, invocationTimeOut = 0) //, expectedExceptions = {NullPointerException.class, AssertionError.class}) + public void testMultiThread() { +/* not implemented testN1Default(); + testN1Comment(); */ + testN2Default(); + testN2Trim(); + testN3Default(); + testN3Prefix(); + testN3Trim(); + testN4Default(); + testN4Trim(); + testN5Default(); + testN5Trim(); + testN6Default(); + testNsPushdownDefault(); + testNsPushdownPrefix(); + testNsDefaultDefault(); + testNsDefaultPrefix(); + testNsSortDefault(); + testNsSortPrefix(); + testNsRedeclDefault(); + testNsRedeclPrefix(); + testNsSuperfluousDefault(); + testNsSuperfluousPrefix(); + testNsXmlDefault(); + testNsXmlPrefix(); + testNsXmlQname(); + testNsXmlPrefixQname(); + testNsContentDefault(); + testNsContentQnameElem(); + testNsContentQnameXpathElem(); + testNsContentPrefixQnameXPathElem(); + } + + // comment and pi not implemented yet +// @Test +// public void testN1Default() { +// Assert.assertTrue(processTest("1", "inC14N1", "c14nDefault")); + // } + + + // comment and pi not implemented yet +// @Test +// public void testN1Comment() { + // Assert.assertTrue(processTest("2", "inC14N1", "c14nComment")); + // } +// + + @Test + public void testN2Default() { + Assert.assertTrue(processTest("3", "inC14N2", "c14nDefault")); + } + + @Test + public void testN2Trim() { + Assert.assertTrue(processTest("4", "inC14N2", "c14nTrim")); + } + + @Test + public void testN21Default() { + Assert.assertTrue(processTest("1r", "inC14N2_1", "c14nDefault")); + } + + @Test + public void testN21Trim() { + Assert.assertTrue(processTest("2r", "inC14N2_1", "c14nTrim")); + } + + @Test + public void testN3Default() { + Assert.assertTrue(processTest("5", "inC14N3", "c14nDefault")); + } + + // + // work with PVDNP_MODE=false + // + + @Test + public void testTemp() { + Assert.assertTrue(processTest("34f", "inC14N2", "c14nDefault")); + } + + @Test + public void testN3Prefix() { + Assert.assertTrue(processTest("6", "inC14N3", "c14nPrefix")); + } + + @Test + public void testN3Trim() { + Assert.assertTrue(processTest("7", "inC14N3", "c14nTrim")); + } + + @Test + public void testN4Default() { + Assert.assertTrue(processTest("8", "inC14N4", "c14nDefault")); + } + + @Test + public void testN4Trim() { + Assert.assertTrue(processTest("9", "inC14N4", "c14nTrim")); + } + + @Test + public void testN5Default() { + Assert.assertTrue(processTest("10", "inC14N5", "c14nDefault")); + } + + @Test + public void testN5Trim() { + Assert.assertTrue(processTest("11", "inC14N5", "c14nTrim")); + } + + + @Test + public void testN6Default() { + Assert.assertTrue(processTest("12", "inC14N6", "c14nDefault")); + } + + @Test + public void testNsPushdownDefault() { + Assert.assertTrue(processTest("13", "inNsPushdown", "c14nDefault")); + } + + @Test + public void testNsPushdownPrefix() { + Assert.assertTrue(processTest("14", "inNsPushdown", "c14nPrefix")); + } + + + @Test + public void testNsDefaultDefault() { + Assert.assertTrue(processTest("15", "inNsDefault", "c14nDefault")); + } + + @Test + public void testNsDefaultPrefix() { + Assert.assertTrue(processTest("16", "inNsDefault", "c14nPrefix")); + } + + + @Test + public void testNsSortDefault() { + Assert.assertTrue(processTest("17", "inNsSort", "c14nDefault")); + } + + @Test + public void testNsSortPrefix() { + Assert.assertTrue(processTest("18", "inNsSort", "c14nPrefix")); + } + + @Test + public void testNsRedeclDefault() { + Assert.assertTrue(processTest("19", "inNsRedecl", "c14nDefault")); + } + + @Test + public void testNsRedeclPrefix() { + Assert.assertTrue(processTest("20", "inNsRedecl", "c14nPrefix")); + } + + + @Test + public void testNsSuperfluousDefault() { + Assert.assertTrue(processTest("21", "inNsSuperfluous", "c14nDefault")); + } + + @Test + public void testNsSuperfluousPrefix() { + Assert.assertTrue(processTest("22", "inNsSuperfluous", "c14nPrefix")); + } + + @Test + public void testNsXmlDefault() { + Assert.assertTrue(processTest("23", "inNsXml", "c14nDefault")); + } + + @Test + public void testNsXmlPrefix() { + Assert.assertTrue(processTest("24", "inNsXml", "c14nPrefix")); + } + + @Test + public void testNsXmlQname() { + Assert.assertTrue(processTest("25", "inNsXml", "c14nQname")); + } + + + @Test + public void testNsXmlPrefixQname() { + Assert.assertTrue(processTest("26", "inNsXml", "c14nPrefixQname")); + } + + @Test + public void testNsContentDefault() { + Assert.assertTrue(processTest("27", "inNsContent", "c14nDefault")); + } + + @Test + public void testNsContentQnameElem() { + Assert.assertTrue(processTest("28", "inNsContent", "c14nQnameElem")); + } + + @Test + public void testNsContentQnameXpathElem() { + Assert.assertTrue(processTest("29", "inNsContent", "c14nQnameXpathElem")); + } + + + @Test + public void testNsContentPrefixQnameXPathElem() { + Assert.assertTrue(processTest("30", "inNsContent", + "c14nPrefixQnameXpathElem")); + } + + @Test + public void testRC242Default() { + Assert.assertTrue(processTest("3r", "inRC2_4_2", "c14nDefault")); + } + + @Test + public void testN22Trim() { + Assert.assertTrue(processTest("4r", "inC14N2_2", "c14nTrim")); + } + + @Test + public void testN22TrimExcl1() { + Assert.assertTrue(processTest("5r", "inC14N2_2", "c14nTrim", + new ICanonicalizerExcludeList() { + + @Override + public String getExcludeListName() { + return "excl1"; + } + + @Override + public List getExcludeList(Document doc) { + NodeList nl = doc.getChildNodes(); + List nodes = new ArrayList(); + nodes.add(nl.item(0).getChildNodes().item(3)); + return nodes; + } + })); + } + + + @Test + public void testN3DefaultExcl2() { + Assert.assertTrue(processTest("7r", "inC14N3", "c14nDefault")); + } + + @Test + public void testNsContent1PrefixQnameXPathElem() { + Assert.assertTrue(processTest("8r", "inNsContent_1", + "c14nPrefixQnameXpathElem")); + } + + + @Test + public void testN22TrimExcl2() { + Assert.assertTrue(processTest("9r", "inC14N2_2", "c14nTrim", + new ICanonicalizerExcludeList() { + + @Override + public String getExcludeListName() { + return "excl2"; + } + + @Override + public List getExcludeList(Document doc) { + NodeList nl = doc.getChildNodes(); + List nodes = new ArrayList(); + Node dirtyNode = nl.item(0).getChildNodes().item(3); + // "xml:" attribute + nodes.add(dirtyNode.getAttributes().item(0)); + // text node + nodes.add(dirtyNode.getChildNodes().item(0)); + return nodes; + } + })); + } + + @Test + public void testWsseDefault() { + Assert.assertTrue(processTest("10r", "inWsse", "c14nDefault")); + } + + @Test + public void testWssePrefix() { + Assert.assertTrue(processTest("11r", "inWsse", "c14nPrefix")); + } + + @Test + public void testN3PrefixIncl1() { + Assert.assertTrue(processTest("12r", "inC14N3", "c14nPrefix", + new ICanonicalizerExcludeList() { + + @Override + public String getExcludeListName() { + return "incl1"; + } + + @Override + public List getIncludeList(Document doc) { + List nodes = new ArrayList(); + NodeList nl = doc.getChildNodes().item(1).getChildNodes(); + // e3 + nodes.add(nl.item(5)); + // e7 + nodes.add(nl.item(11).getChildNodes().item(1)); + return nodes; + } + })); + } + + // accoding to xml-c14n2-testcases: 3.2 Default namespace declarations + // wrong test + // + // @Test + // public void testNsDefault1Prefix() { + // Assert.assertTrue(processTest("14r", "inNsDefault_1", "c14nPrefix")); + // } + + + @Test + public void testFlyXmlDefault() { + try { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.newDocument(); + + Node root = doc.createElement("doc"); + doc.appendChild(root); + + Element n1 = doc.createElement("b:doc1"); + root.appendChild(n1); + + Attr n1a1 = doc.createAttribute("xmlns:a"); + n1a1.setValue("http://a"); + n1.setAttributeNode(n1a1); + Attr n1a2 = doc.createAttribute("xmlns:b"); + n1a2.setValue("http://b"); + n1.setAttributeNode(n1a2); + Attr n1a3 = doc.createAttribute("attr"); + n1a3.setValue("attr1"); + n1.setAttributeNode(n1a3); + + Element n11 = doc.createElement("doc11"); + n1.appendChild(n11); + + Attr n11a1 = doc.createAttribute("a:attr"); + n11a1.setValue("attr2"); + n11.setAttributeNode(n11a1); + + String path = CanonicalizerTest.class.getProtectionDomain() + .getCodeSource().getLocation().getPath(); + Assert.assertTrue(processTest("13r", doc, path, "inFlyXml", + "c14nDefault", null)); + } catch (Exception e) { + e.printStackTrace(); + Assert.assertFalse(false); + } + } + + private static boolean processTest(String testNumber, String inFileName, + String paramName) { + return processTest(testNumber, inFileName, paramName, null); + } + + private static boolean processTest(String testNumber, String inFileName, + String paramName, ICanonicalizerExcludeList iExcludeList) { + try { + /*EntityResolver entityResolver = new EntityResolver() { + @Override + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException, IOException { + if (systemId.contains("doc.dtd")) { + return new InputSource(new ByteArrayInputStream("".getBytes())); + } else + return null; + } + };*/ + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + + //dBuilder.setEntityResolver(entityResolver); + + /* + + работает с maven, не работает с gradle + + String path = CanonicalizerTest.class.getProtectionDomain() + .getCodeSource().getLocation().getPath(); + */ + + String path = CanonicalizerTest.class.getProtectionDomain().getClassLoader().getResource(inFileName+".xml").getPath(); + path = path.substring(0, path.indexOf(inFileName)); + + Document doc = dBuilder.parse(new FileInputStream(path + inFileName + + ".xml")); + return processTest(testNumber, doc, path, inFileName, paramName, + iExcludeList); + } catch (Throwable e) { + e.printStackTrace(); + } + return false; + } + + private static boolean processTest(String testNumber, Document doc, + String path, String inFileName, String paramName, + ICanonicalizerExcludeList iExInCludeList) throws Exception { + long l = System.currentTimeMillis(); + String result = ""; + List includeList = iExInCludeList != null ? iExInCludeList + .getIncludeList(doc) : null; + List excludeList = iExInCludeList != null ? iExInCludeList + .getExcludeList(doc) : null; + if (includeList != null) { + if (excludeList != null) { + result = DOMCanonicalizer.canonicalize(doc, includeList, excludeList, + getParams(paramName)); + } else { + result = DOMCanonicalizer.canonicalize(doc, includeList, + getParams(paramName)); + } + } else { + if (excludeList != null) { + result = DOMCanonicalizer.canonicalize(doc, null, excludeList, + getParams(paramName)); + } else { + result = DOMCanonicalizer.canonicalize(doc, getParams(paramName)); } - return nodes; - } - })); - } - - @Test - public void testN3DefaultExcl2() { - Assert.assertTrue(processTest("7r", "inC14N3", "c14nDefault", - new ICanonicalizerExcludeList() { - - @Override - public String getExcludeListName() { - return "excl2"; - } - - @Override - public List getExcludeList(Document doc) { - NodeList nl = doc.getChildNodes(); - List nodes = new ArrayList(); - NamedNodeMap e5Attrs = nl.item(1).getChildNodes().item(9) - .getAttributes(); - String[] names = new String[] { "a:attr", "attr", "xmlns:a" }; - for (String name : names) { - nodes.add(e5Attrs.getNamedItem(name)); + } + l = System.currentTimeMillis() - l; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + FileInputStream fis = new FileInputStream( + path + + "out_" + + inFileName + + "_" + + paramName + + (excludeList != null || includeList != null ? ("_" + iExInCludeList + .getExcludeListName()) : "") + ".xml"); + byte[] bytes = new byte[1024]; + int cnt = 0; + while ((cnt = fis.read(bytes)) > -1) + baos.write(bytes, 0, cnt); + fis.close(); + baos.flush(); + baos.close(); + boolean b = l <= 200; + for (int i = 0; b && i < result.length(); i++) { + if (result.getBytes("UTF-8")[i] != baos.toByteArray()[i]) { + System.out.println("Error pos: " + i + " res:" + + result.getBytes("UTF-8")[i] + " base:" + baos.toByteArray()[i]); + b = false; } - return nodes; - } - })); - } - - @Test - public void testNsContent1PrefixQnameXPathElem() { - Assert.assertTrue(processTest("8r", "inNsContent_1", - "c14nPrefixQnameXpathElem")); - } - - @Test - public void testN22TrimExcl2() { - Assert.assertTrue(processTest("9r", "inC14N2_2", "c14nTrim", - new ICanonicalizerExcludeList() { - - @Override - public String getExcludeListName() { - return "excl2"; - } - - @Override - public List getExcludeList(Document doc) { - NodeList nl = doc.getChildNodes(); - List nodes = new ArrayList(); - Node dirtyNode = nl.item(0).getChildNodes().item(3); - // "xml:" attribute - nodes.add(dirtyNode.getAttributes().item(0)); - // text node - nodes.add(dirtyNode.getChildNodes().item(0)); - return nodes; - } - })); - } - - @Test - public void testWsseDefault() { - Assert.assertTrue(processTest("10r", "inWsse", "c14nDefault")); - } - - @Test - public void testWssePrefix() { - Assert.assertTrue(processTest("11r", "inWsse", "c14nPrefix")); - } - - @Test - public void testN3PrefixIncl1() { - Assert.assertTrue(processTest("12r", "inC14N3", "c14nPrefix", - new ICanonicalizerExcludeList() { - - @Override - public String getExcludeListName() { - return "incl1"; - } - - @Override - public List getIncludeList(Document doc) { - List nodes = new ArrayList(); - NodeList nl = doc.getChildNodes().item(1).getChildNodes(); - // e3 - nodes.add(nl.item(5)); - // e7 - nodes.add(nl.item(11).getChildNodes().item(1)); - return nodes; - } - })); - } - - @Test - public void testFlyXmlDefault() { - try { - DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); - Document doc = dBuilder.newDocument(); - - Node root = doc.createElement("doc"); - doc.appendChild(root); - - Element n1 = doc.createElement("b:doc1"); - root.appendChild(n1); - - Attr n1a1 = doc.createAttribute("xmlns:a"); - n1a1.setValue("http://a"); - n1.setAttributeNode(n1a1); - Attr n1a2 = doc.createAttribute("xmlns:b"); - n1a2.setValue("http://b"); - n1.setAttributeNode(n1a2); - Attr n1a3 = doc.createAttribute("attr"); - n1a3.setValue("attr1"); - n1.setAttributeNode(n1a3); - - Element n11 = doc.createElement("doc11"); - n1.appendChild(n11); - - Attr n11a1 = doc.createAttribute("a:attr"); - n11a1.setValue("attr2"); - n11.setAttributeNode(n11a1); - - String path = CanonicalizerTest.class.getProtectionDomain() - .getCodeSource().getLocation().getPath(); - Assert.assertTrue(processTest("13r", doc, path, "inFlyXml", - "c14nDefault", null)); - } catch (Exception e) { - e.printStackTrace(); - Assert.assertFalse(false); - } - } - - @Test - public void testNsDefault1Prefix() { - Assert.assertTrue(processTest("14r", "inNsDefault_1", "c14nPrefix")); - } - - private static boolean processTest(String testNumber, String inFileName, - String paramName) { - return processTest(testNumber, inFileName, paramName, null); - } - - private static boolean processTest(String testNumber, String inFileName, - String paramName, ICanonicalizerExcludeList iExcludeList) { - try { - DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); - - String path = CanonicalizerTest.class.getProtectionDomain() - .getCodeSource().getLocation().getPath(); - - Document doc = dBuilder.parse(new FileInputStream(path + inFileName - + ".xml")); - return processTest(testNumber, doc, path, inFileName, paramName, - iExcludeList); - } catch (Throwable e) { - e.printStackTrace(); - } - return false; - } - - private static boolean processTest(String testNumber, Document doc, - String path, String inFileName, String paramName, - ICanonicalizerExcludeList iExInCludeList) throws Exception { - long l = System.currentTimeMillis(); - String result = ""; - List includeList = iExInCludeList != null ? iExInCludeList - .getIncludeList(doc) : null; - List excludeList = iExInCludeList != null ? iExInCludeList - .getExcludeList(doc) : null; - if (includeList != null) { - if (excludeList != null) { - result = DOMCanonicalizer.canonicalize(doc, includeList, excludeList, - getParams(paramName)); - } else { - result = DOMCanonicalizer.canonicalize(doc, includeList, - getParams(paramName)); - } - } else { - if (excludeList != null) { - result = DOMCanonicalizer.canonicalize(doc, null, excludeList, - getParams(paramName)); - } else { - result = DOMCanonicalizer.canonicalize(doc, getParams(paramName)); - } - } - l = System.currentTimeMillis() - l; - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - FileInputStream fis = new FileInputStream( - path - + "out_" - + inFileName - + "_" - + paramName - + (excludeList != null || includeList != null ? ("_" + iExInCludeList - .getExcludeListName()) : "") + ".xml"); - byte[] bytes = new byte[1024]; - int cnt = 0; - while ((cnt = fis.read(bytes)) > -1) - baos.write(bytes, 0, cnt); - fis.close(); - baos.flush(); - baos.close(); - boolean b = l <= 200; - for (int i = 0; b && i < result.length(); i++) { - if (result.getBytes("UTF-8")[i] != baos.toByteArray()[i]) { - System.out.println("Error pos: " + i + " res:" - + result.getBytes("UTF-8")[i] + " base:" + baos.toByteArray()[i]); - b = false; - } - } - if (!b) { - System.out.println("---Result---\n" + baos.toString("UTF-8") - + "\n---Base---\n" + result + "---time---\n" + l / 1000.0 - + "\n------"); - } else { - System.out.println("Test " + testNumber + " (" + l / 1000.0 - + " sec) – ok"); - } - return b; - } - - private static Parameters getParams(String paramName) { - Parameters params = new Parameters(); - if ("c14nDefault".equals(paramName)) { - } else if ("c14nComment".equals(paramName)) { - params.setIgnoreComments(false); - } else if ("c14nTrim".equals(paramName)) { - params.setTrimTextNodes(true); - } else if ("c14nPrefix".equals(paramName)) { - params.setPrefixRewrite(Parameters.SEQUENTIAL); - } else if ("c14nQname".equals(paramName)) { - params.getQnameAwareAttributes().add( - new QNameAwareParameter("type", - "http://www.w3.org/2001/XMLSchema-instance")); - } else if ("c14nPrefixQname".equals(paramName)) { - params.setPrefixRewrite(Parameters.SEQUENTIAL); - params.getQnameAwareAttributes().add( - new QNameAwareParameter("type", - "http://www.w3.org/2001/XMLSchema-instance")); - } else if ("c14nQnameElem".equals(paramName)) { - params.getQnameAwareElements().add( - new QNameAwareParameter("bar", "http://a")); - } else if ("c14nQnameXpathElem".equals(paramName)) { - params.getQnameAwareElements().add( - new QNameAwareParameter("bar", "http://a")); - params.getQnameAwareXPathElements().add( - new QNameAwareParameter("IncludedXPath", - "http://www.w3.org/2010/xmldsig2#")); - } else if ("c14nPrefixQnameXpathElem".equals(paramName)) { - params.setPrefixRewrite(Parameters.SEQUENTIAL); - params.getQnameAwareElements().add( - new QNameAwareParameter("bar", "http://a")); - params.getQnameAwareXPathElements().add( - new QNameAwareParameter("IncludedXPath", - "http://www.w3.org/2010/xmldsig2#")); - } - return params; - } + } + if (!b) { + System.out.println("---Result---\n" + result + + "\n---Base---\n" + baos.toString("UTF-8") + "\n---time---\n" + l / 1000.0 + + "\n------"); + + /* + java.io.FileOutputStream res = new FileOutputStream("./result"); + res.write(result.getBytes()); + res.close(); + + java.io.FileOutputStream base = new FileOutputStream("./base"); + base.write(baos.toByteArray()); + base.close(); +*/ + + } else { + System.out.println("Test " + testNumber + " (" + l / 1000.0 + + " sec) – ok"); + } + return b; + } + + private static Parameters getParams(String paramName) { + Parameters params = new Parameters(); + if ("c14nDefault".equals(paramName)) { + } else if ("c14nComment".equals(paramName)) { + params.setIgnoreComments(false); + } else if ("c14nTrim".equals(paramName)) { + params.setTrimTextNodes(true); + } else if ("c14nPrefix".equals(paramName)) { + params.setPrefixRewrite(Parameters.SEQUENTIAL); + } else if ("c14nQname".equals(paramName)) { + params.getQnameAwareQualifiedAttributes().add( + new QNameAwareParameter("type", + "http://www.w3.org/2001/XMLSchema-instance")); + } else if ("c14nPrefixQname".equals(paramName)) { + params.setPrefixRewrite(Parameters.SEQUENTIAL); + params.getQnameAwareQualifiedAttributes().add( + new QNameAwareParameter("type", + "http://www.w3.org/2001/XMLSchema-instance")); + } else if ("c14nQnameElem".equals(paramName)) { + params.getQnameAwareElements().add( + new QNameAwareParameter("bar", "http://a")); + } else if ("c14nQnameXpathElem".equals(paramName)) { + params.getQnameAwareElements().add( + new QNameAwareParameter("bar", "http://a")); + params.getQnameAwareXPathElements().add( + new QNameAwareParameter("IncludedXPath", + "http://www.w3.org/2010/xmldsig2#")); + } else if ("c14nPrefixQnameXpathElem".equals(paramName)) { + params.setPrefixRewrite(Parameters.SEQUENTIAL); + params.getQnameAwareElements().add( + new QNameAwareParameter("bar", "http://a")); + params.getQnameAwareXPathElements().add( + new QNameAwareParameter("IncludedXPath", + "http://www.w3.org/2010/xmldsig2#")); + } + return params; + } } \ No newline at end of file diff --git a/src/test/resources/inQNameTextWithWhiteSpaces.xml b/src/test/resources/inQNameTextWithWhiteSpaces.xml new file mode 100644 index 0000000..2de9dd5 --- /dev/null +++ b/src/test/resources/inQNameTextWithWhiteSpaces.xml @@ -0,0 +1,8 @@ + + + b1:Form + +1000200012015070600000503 + + + diff --git a/src/test/resources/out_inQNameTextWithWhiteSpaces_QNameAwareParameterWithWhiteSpace.xml b/src/test/resources/out_inQNameTextWithWhiteSpaces_QNameAwareParameterWithWhiteSpace.xml new file mode 100644 index 0000000..4b6327b --- /dev/null +++ b/src/test/resources/out_inQNameTextWithWhiteSpaces_QNameAwareParameterWithWhiteSpace.xml @@ -0,0 +1 @@ +n2:Form1000200012015070600000503 \ No newline at end of file diff --git a/viewgif.exe b/viewgif.exe deleted file mode 100644 index e69de29..0000000