first commit
This commit is contained in:
commit
4d332ef662
27586 changed files with 3281783 additions and 0 deletions
6
rus/WEB-INF/lib/docx4j-3.2.1_src/META-INF/MANIFEST.MF
Normal file
6
rus/WEB-INF/lib/docx4j-3.2.1_src/META-INF/MANIFEST.MF
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Manifest-Version: 1.0
|
||||
Archiver-Version: Plexus Archiver
|
||||
Created-By: Apache Maven
|
||||
Built-By: jharrop
|
||||
Build-Jdk: 1.7.0
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#Generated by Maven
|
||||
#Fri Oct 03 12:17:25 EST 2014
|
||||
version=3.2.1
|
||||
groupId=org.docx4j
|
||||
artifactId=docx4j
|
||||
|
|
@ -0,0 +1,894 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.sonatype.oss</groupId>
|
||||
<artifactId>oss-parent</artifactId>
|
||||
<version>7</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.docx4j</groupId>
|
||||
<artifactId>docx4j</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>docx4j</name>
|
||||
<description>
|
||||
docx4j is a library which helps you to work with the Office Open
|
||||
XML file format as used in docx
|
||||
documents, pptx presentations, and xlsx spreadsheets.
|
||||
</description>
|
||||
<url>http://www.docx4java.org/</url>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache 2</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
<comments>A business-friendly OSS license</comments>
|
||||
</license>
|
||||
</licenses>
|
||||
<scm>
|
||||
<developerConnection>scm:git|git@github.com:plutext/docx4j.git</developerConnection>
|
||||
</scm>
|
||||
<inceptionYear>2007</inceptionYear>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>jharrop</id>
|
||||
<name>Jason Harrop</name>
|
||||
<email>jason@plutext.org</email>
|
||||
<organization>Plutext</organization>
|
||||
<roles>
|
||||
<role>Developer</role>
|
||||
</roles>
|
||||
<timezone>+10</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
<contributors>
|
||||
<contributor>
|
||||
<name>Adam Schmideg</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Albert Aymerich</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>alberto</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>amdonov</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Antoine</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Arnaud Kleinpeter</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>azeloro</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Dave Brown</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Holger Schlegel</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Jeromy Evans</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Jojada Tirtowidjojo</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Leigh</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Manimala Kumar</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Marcel</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Patrick Linskey</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Pierre</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>ppa_waw</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Richard</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Serge Grachov</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Tinne</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>y.rolland</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>denys.zhosan</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Anton Reshetnikov</name>
|
||||
</contributor>
|
||||
</contributors>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- github server corresponds to entry in ~/.m2/settings.xml -->
|
||||
<github.global.server>github</github.global.server>
|
||||
</properties>
|
||||
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
<testSourceDirectory>src/test/java</testSourceDirectory>
|
||||
<outputDirectory>bin</outputDirectory><!-- for a clean jar, be sure to avoid mixing mvn and eclipse output -->
|
||||
<testOutputDirectory>bin-testOutput</testOutputDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>1.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>src/pptx4j/java</source>
|
||||
<source>src/xlsx4j/java</source>
|
||||
<source>src/glox4j/java</source>
|
||||
<source>src/diffx</source>
|
||||
<!-- <source>src/xslfo</source> -->
|
||||
<!-- <source>src/svg</source> -->
|
||||
<!--source>src/sun</source -->
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<configuration>
|
||||
<!-- The objective is to generate a jar which is compatible with Java
|
||||
1.5, whilst at the same time allowing @Override annotations in the source
|
||||
code on methods which merely implement an interface (Java 6 allows this,
|
||||
but 1.5 gives an error). When I played around with this, I found that both
|
||||
maven and ant would happily compile to target 1.5 with the pesky @Override
|
||||
annotations present (irrespective of whether source was set to 1.5 or 1.6).
|
||||
You are not allowed source=1.6, target=1.5; this results in: Failure executing
|
||||
javac, but could not parse the error javac: source release 1.6 requires target
|
||||
release 1.6 So we need source=1.5, target=1.5 The downside is that m2eclipse
|
||||
mirrors this in Eclipse's compiler settings, and Eclipse then complains about
|
||||
the @Override annotations :-( So you must manually change the Eclipse compiler
|
||||
setting back to 1.6. -->
|
||||
<source>1.5</source>
|
||||
<target>1.5</target>
|
||||
|
||||
<verbose>false</verbose>
|
||||
<!-- maxmemory>512m</maxmemory On Linux, use: MAVEN_OPTS="-Xmx512m" mvn install -->
|
||||
<!-- try to help maven to find package com.sun.xml.internal.bind.marshaller:
|
||||
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath> but this doesn't help -->
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<!-- The Surefire Plugin is used during the test phase of the build lifecycle
|
||||
to execute the unit tests of an application -->
|
||||
<version>2.6</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/samples/*.java</exclude>
|
||||
<exclude>**/AbstractNumberingTest.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.3.1</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<!-- the below are prob not necessary, now that we are building from bin-mvn, and so avoiding stuff Eclipse puts into bin dir -->
|
||||
<exclude>**/*.docx</exclude><!-- docx files in /src/test/resources add unwanted 1 MB to jar. -->
|
||||
<exclude>src/test/resources/**/*</exclude>
|
||||
<exclude>src/main/resources/README.txt</exclude><!-- sample log4j.xml and docx4j.properties are now in src/samples/_resources-->
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<!-- The Source Plugin creates a jar archive of the source files of the
|
||||
current project. -->
|
||||
<version>2.1.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- maven-javadoc-plugin seems to require large -Xmx so comment this
|
||||
out if your build is failing because you don't have enough. -->
|
||||
<plugin>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.8</version>
|
||||
<configuration>
|
||||
<maxmemory>512m</maxmemory>
|
||||
<!-- 18 MB without the exclusion; still 15MB with -->
|
||||
<!-- <excludePackageNames>org.plutext.jaxb.svg11:org.plutext.jaxb.xslfo</excludePackageNames> -->
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.soebes.maven.plugins</groupId>
|
||||
<artifactId>maven-echo-plugin</artifactId>
|
||||
<version>0.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>install-echo</id>
|
||||
<phase>install</phase>
|
||||
<goals>
|
||||
<goal>echo</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>deploy-echo</id>
|
||||
<phase>deploy</phase>
|
||||
<goals>
|
||||
<goal>echo</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<echos>
|
||||
<echo>+-------------------------------------------------------+</echo>
|
||||
<echo>! Join the docx4j developers mailing list by !</echo>
|
||||
<echo>! emailing docx4j-dev-subscribe@docx4java.org !</echo>
|
||||
<echo>+-------------------------------------------------------+</echo>
|
||||
</echos>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<versionRange>[1.3,2.0)</versionRange>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<execute>
|
||||
<runOnIncremental>true</runOnIncremental>
|
||||
</execute>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<resources>
|
||||
<!-- be sure to get xml,xlst resources in various src trees -->
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.xslt</include>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/pptx4j/java</directory>
|
||||
<includes>
|
||||
<include>**/*.xslt</include>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/xlsx4j/java</directory>
|
||||
<includes>
|
||||
<include>**/*.xslt</include>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<!--
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>docx4j.properties</include>
|
||||
</includes>
|
||||
</resource>
|
||||
-->
|
||||
<!-- <resource> <directory>src/test/resources</directory> <excludes> <exclude>*.docx</exclude>
|
||||
</excludes> </resource> -->
|
||||
</resources>
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.8</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>standard-javadoc</id>
|
||||
<inherited>true</inherited>
|
||||
<configuration>
|
||||
<description>
|
||||
docx4j Open XML manipulation library
|
||||
</description>
|
||||
<docfilessubdirs>true</docfilessubdirs>
|
||||
<failOnError>false</failOnError>
|
||||
<locale>en_AU</locale>
|
||||
<name>Javadoc report</name>
|
||||
<quiet>true</quiet>
|
||||
<serialwarn>false</serialwarn>
|
||||
<show>private</show>
|
||||
<source>1.6</source>
|
||||
<stylesheet>maven</stylesheet>
|
||||
<version>true</version>
|
||||
</configuration>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- To use MOXy, uncomment the following 2 dependencies.
|
||||
Dependency version 2.4.1 had some issues,
|
||||
see http://www.docx4java.org/forums/docx-java-f6/moxy-t1242.html for further
|
||||
details.
|
||||
|
||||
<dependency>
|
||||
<groupId>org.docx4j</groupId>
|
||||
<artifactId>docx4j-MOXy-JAXBContext</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
<artifactId>org.eclipse.persistence.moxy</artifactId>
|
||||
<version>2.5.1</version>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
<!-- Uncomment this if you are using Java 5.
|
||||
|
||||
StAX reference implementation,
|
||||
required for MLInputFactory.newInstance() in Differencer
|
||||
iff you are using Java 1.5
|
||||
(not necessary for Java 6)
|
||||
-->
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>stax</groupId>
|
||||
<artifactId>stax</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>stax</groupId>
|
||||
<artifactId>stax-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency> -->
|
||||
<!-- stax 1.2.0 grabs 1.0.1(!); jaxb would grab 1.0.2 (where from?) -->
|
||||
|
||||
<!-- Uncomment this for Java 5
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>2.1.3</version>
|
||||
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.plutext</groupId>
|
||||
<artifactId>jaxb-svg11</artifactId><!-- previously part of docx4j source -->
|
||||
<version>1.0.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.plutext</groupId>
|
||||
<artifactId>jaxb-xslfo</artifactId><!-- previously part of docx4j source -->
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.plutext</groupId>
|
||||
<artifactId>jaxb-xmldsig-core</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- events -->
|
||||
<dependency>
|
||||
<groupId>net.engio</groupId>
|
||||
<artifactId>mbassador</artifactId>
|
||||
<version>1.1.10</version>
|
||||
</dependency>
|
||||
|
||||
<!-- From 3.0, docx4j uses slf4j -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.5</version>
|
||||
</dependency>
|
||||
|
||||
<!-- instead of FOP's commons-logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.5</version>
|
||||
</dependency>
|
||||
|
||||
<!-- .. default to log4j implementation, just like docx4j 2.8.1 and earlier. -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.7.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.17</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>mail</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.jms</groupId>
|
||||
<artifactId>jms</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jdmk</groupId>
|
||||
<artifactId>jmxtools</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jmx</groupId>
|
||||
<artifactId>jmxri</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<!-- required for our diffx -->
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- required for ole introspection -->
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>1.3.1</version> <!-- 2.2 works -->
|
||||
</dependency>
|
||||
|
||||
<!-- To use a version of FOP more recent than 1.1
|
||||
(eg built from source), comment out
|
||||
xmlgraphics-commons:1.5 and fop below,
|
||||
and add the following classes to your
|
||||
class path:
|
||||
|
||||
http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/lib/batik-all-1.7.jar
|
||||
(there is probably something in maven
|
||||
|
||||
http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/lib/xmlgraphics-commons-svn-trunk.jar
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.xmlgraphics</groupId>
|
||||
<artifactId>xmlgraphics-commons</artifactId>
|
||||
<version>1.5</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.xmlgraphics</groupId>
|
||||
<artifactId>fop</artifactId>
|
||||
<version>1.1</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>avalon-framework-api</artifactId>
|
||||
<groupId>org.apache.avalon.framework</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>avalon-framework-impl</artifactId>
|
||||
<groupId>org.apache.avalon.framework</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>xml-apis</groupId>
|
||||
<artifactId>xml-apis</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>xml-apis</groupId>
|
||||
<artifactId>xml-apis-ext</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- these two are to correct issues in fop dependency -->
|
||||
<dependency>
|
||||
<groupId>org.apache.avalon.framework</groupId>
|
||||
<artifactId>avalon-framework-api</artifactId>
|
||||
<version>4.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.avalon.framework</groupId>
|
||||
<artifactId>avalon-framework-impl</artifactId>
|
||||
<version>4.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xalan</groupId>
|
||||
<artifactId>xalan</artifactId>
|
||||
<version>2.7.1</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>xml-apis</groupId>
|
||||
<artifactId>xml-apis</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- These work for basic marshalling/unmarshalling,
|
||||
but not with our XSLT extension functions.
|
||||
<dependency>
|
||||
<groupId>net.sf.saxon</groupId>
|
||||
<artifactId>saxon</artifactId>
|
||||
<version>8.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.saxon</groupId>
|
||||
<artifactId>saxon-dom</artifactId>
|
||||
<version>8.7</version>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
<dependency>
|
||||
<groupId>net.arnx</groupId>
|
||||
<artifactId>wmf2svg</artifactId>
|
||||
<version>0.9.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-scratchpad</artifactId>
|
||||
<version>3.8</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Ensure both the Java 6 and RI interfaces are present,
|
||||
even if the user has just one.
|
||||
NB: this (or an added source location containing them) is
|
||||
necessary (at least for Maven 2.2.1) since without this,
|
||||
Maven doesn't find the Java 6 copy in rt.jar -->
|
||||
<dependency>
|
||||
<groupId>com.googlecode.jaxb-namespaceprefixmapper-interfaces</groupId>
|
||||
<artifactId>JAXBNamespacePrefixMapper</artifactId>
|
||||
<version>2.2.4</version>
|
||||
<!-- http://dev.plutext.org/forums/docx-java-f6/dependency-management-improvements-t739.html -->
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr-runtime</artifactId>
|
||||
<version>3.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>stringtemplate</artifactId>
|
||||
<version>3.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- since 3.1.1 -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>17.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Uncomment for load/save via JCR, which
|
||||
may be found in docx4j-extras.
|
||||
<dependency>
|
||||
<groupId>javax.jcr</groupId>
|
||||
<artifactId>jcr</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
|
||||
<!-- Uncomment for the PDF conversion via HTML or iText, which
|
||||
may be found in docx4j-extras.
|
||||
|
||||
If you are planning to use that, you'll also want to uncomment
|
||||
the BaseFont stuff in PhysicalFonts.
|
||||
|
||||
<dependency>
|
||||
<groupId>com.lowagie</groupId>
|
||||
<artifactId>itext-unsigned</artifactId>
|
||||
<version>2.0.8</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>bouncycastle</artifactId>
|
||||
<groupId>bcmail-jdk14</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>bouncycastle</artifactId>
|
||||
<groupId>bcprov-jdk14</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
|
||||
<!-- Uncomment for the PDF conversion via HTML, which
|
||||
may be found in docx4j-extras.
|
||||
|
||||
<dependency>
|
||||
<groupId>pdf-renderer</groupId>
|
||||
<artifactId>pdf-renderer</artifactId>
|
||||
<version>0.2009.0324</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xhtmlrenderer</groupId>
|
||||
<artifactId>minium</artifactId>
|
||||
<version>0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>xhtmlrenderer</groupId>
|
||||
<artifactId>core-renderer</artifactId>
|
||||
<version>R8pre2</version>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
|
||||
|
||||
<!-- if you want to use the vfs stuff in docx4j-extras, you'll need commons-vfs
|
||||
(one of the two versions below), and jdom.
|
||||
|
||||
required by commons-vfs;
|
||||
TODO that POM should declare this.
|
||||
<dependency>
|
||||
<groupId>jdom</groupId>
|
||||
<artifactId>jdom</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-vfs</groupId>
|
||||
<artifactId>commons-vfs</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
This patched version of VFS is required for WebDAV
|
||||
|
||||
In the meantime, this may be found in
|
||||
https://webdavclient4j.svn.sourceforge.net/svnroot/webdavclient4j/trunk/m2/org/apache/commons/commons-vfs-patched/
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-vfs-patched</artifactId>
|
||||
<version>1.9.1</version>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
|
||||
<!-- svn:http://dev.plutext.org/svn/docx4j/trunk/docx4j/m2
|
||||
|
||||
(stuff not available in public repositories)
|
||||
|
||||
mvn deploy:deploy-file -f wagon-svn-pom.xml -Dfile=dist/docx4j.jar -DpomFile=pom.xml -Dpackaging=jar -DrepositoryId=docx4j -Durl=svn:http://dev.plutext.org/svn/docx4j/trunk/docx4j/m2
|
||||
|
||||
-->
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
<profiles> <!-- use -P eg mvn -Psign-artifacts -->
|
||||
<profile>
|
||||
<id>sign-artifacts</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
|
||||
<!-- Deploy a snapshot to GitHub
|
||||
|
||||
See http://stackoverflow.com/questions/14013644/hosting-a-maven-repository-on-github
|
||||
|
||||
To do this:
|
||||
0. change outputDirectory, for a clean jar
|
||||
1. comment out parent element (top of pom), since this is what makes deploy push to https://oss.sonatype.org
|
||||
2. comment out maven-javadoc-plugin, since its not worth bothering with that large upload
|
||||
3. execute
|
||||
|
||||
mvn clean deploy -DskipTests -Pgithub-mvn-repo
|
||||
|
||||
-->
|
||||
<profile>
|
||||
<id>github-mvn-repo</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.github.github</groupId>
|
||||
<artifactId>site-maven-plugin</artifactId>
|
||||
<version>0.8</version>
|
||||
<configuration>
|
||||
<message>Maven artifacts for ${project.version}</message> <!-- git commit message -->
|
||||
<noJekyll>true</noJekyll> <!-- disable webpage processing -->
|
||||
<outputDirectory>${project.build.directory}/mvn-repo</outputDirectory> <!-- matches distribution management repository url above -->
|
||||
<branch>refs/heads/mvn-repo</branch> <!-- remote branch name -->
|
||||
<includes><include>**/*</include></includes>
|
||||
<repositoryName>docx4j</repositoryName> <!-- github repo name -->
|
||||
<repositoryOwner>plutext</repositoryOwner> <!-- github username -->
|
||||
</configuration>
|
||||
<executions>
|
||||
<!-- run site-maven-plugin's 'site' target as part of the build's normal 'deploy' phase -->
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>site</goal>
|
||||
</goals>
|
||||
<phase>deploy</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
|
||||
<!-- comment this out, until the Windows path issues below are fixed in m2eclipse
|
||||
<profile>
|
||||
<id>jdk15</id>
|
||||
<activation>
|
||||
<jdk>1.5</jdk>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>2.1.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>jdk16</id>
|
||||
<activation>
|
||||
<jdk>1.6</jdk>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>2.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${env.JAVA_HOME}/jre/lib/rt.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
-->
|
||||
|
||||
</profiles>
|
||||
|
||||
<!--
|
||||
<systemPath>
|
||||
/usr/lib/jvm/java-6-sun/jre/lib/rt.jar
|
||||
</systemPath>
|
||||
Note for Windows users: Maven won't find rt.jar if systemPath
|
||||
contains a space (eg "Program Files"). Either copy rt.jar
|
||||
to a path that doesn't contain spaces, or use:
|
||||
|
||||
<systemPath>${env.JAVA_HOME}/jre/lib/rt.jar</systemPath>
|
||||
|
||||
which works on the command line, but not in m2eclipse 0.9.x.
|
||||
See http://jira.codehaus.org/browse/MNGECLIPSE-581
|
||||
|
||||
<systemPath>${java.home}/lib/rt.jar</systemPath>
|
||||
broken (mvn 2.0.9) even though java.home is supposed to point to JRE_HOME:
|
||||
|
||||
-->
|
||||
|
||||
<!-- Uncomment to deploy to GitHub. MUST Comment out for real release
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>internal.repo</id>
|
||||
<name>Temporary Staging Repository</name>
|
||||
<url>file://${project.build.directory}/mvn-repo</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
-->
|
||||
</project>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.topologi.diffx;
|
||||
|
||||
public class DiffXException extends Exception {
|
||||
private static final long serialVersionUID = 3572025323967229569L;
|
||||
|
||||
public DiffXException() {}
|
||||
|
||||
public DiffXException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DiffXException(Exception ex) {
|
||||
super(ex);
|
||||
}
|
||||
|
||||
public DiffXException(String message, Exception ex) {
|
||||
super(message, ex);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
package com.topologi.diffx;
|
||||
|
||||
import com.topologi.diffx.algorithm.DiffXAlgorithm;
|
||||
import com.topologi.diffx.algorithm.DiffXFitopsy;
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.impl.CommentEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.format.SmartXMLFormatter;
|
||||
import com.topologi.diffx.load.DOMRecorder;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import com.topologi.diffx.sequence.SequenceSlicer;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.eclipse.compare.EventSequenceComparator;
|
||||
import org.eclipse.compare.rangedifferencer.RangeDifference;
|
||||
import org.eclipse.compare.rangedifferencer.RangeDifferencer;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
public class Docx4jDriver {
|
||||
public static final boolean debug = false;
|
||||
|
||||
public static void log(String message, boolean force) {
|
||||
if (force)
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
public static void log(String message) {
|
||||
log(message, false);
|
||||
}
|
||||
|
||||
public static void formatEventSequence(EventSequence eventSequence, DiffXFormatter formatter) throws NullPointerException, IOException {
|
||||
List<DiffXEvent> sequence = eventSequence.events();
|
||||
DiffXEvent x = null;
|
||||
for (int i = 0; i < sequence.size(); i++) {
|
||||
x = sequence.get(i);
|
||||
formatter.format(x);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addToPrefixMapping(PrefixMapping to, PrefixMapping others) throws NullPointerException {
|
||||
for (Enumeration<String> e = others.getURIs(); e.hasMoreElements(); ) {
|
||||
String key = e.nextElement();
|
||||
to.add(key, others.getPrefix(key));
|
||||
}
|
||||
}
|
||||
|
||||
public static void mainDiff(EventSequence seq1, EventSequence seq2, SmartXMLFormatter formatter, DiffXConfig config) throws DiffXException, IOException {
|
||||
formatter.declarePrefixMapping(seq1.getPrefixMapping());
|
||||
formatter.declarePrefixMapping(seq2.getPrefixMapping());
|
||||
if (config != null)
|
||||
formatter.setConfig(config);
|
||||
SequenceSlicer slicer = new SequenceSlicer(seq1, seq2);
|
||||
slicer.slice();
|
||||
slicer.formatStart(formatter);
|
||||
DiffXAlgorithm df = new DiffXFitopsy(seq1, seq2);
|
||||
df.process(formatter);
|
||||
slicer.formatEnd(formatter);
|
||||
}
|
||||
|
||||
public static void diff(Node xml1, Node xml2, Writer out) throws DiffXException, IOException {
|
||||
try {
|
||||
DiffXConfig diffxConfig = new DiffXConfig();
|
||||
diffxConfig.setIgnoreWhiteSpace(false);
|
||||
diffxConfig.setPreserveWhiteSpace(true);
|
||||
log(xml1.getNodeName());
|
||||
log("" + xml1.getChildNodes().getLength());
|
||||
log(xml2.getNodeName());
|
||||
log("" + xml2.getChildNodes().getLength());
|
||||
if (!xml1.getNodeName().equals(xml2.getNodeName()) || (xml1.getChildNodes().getLength() <= 3 && xml2.getChildNodes().getLength() <= 3)) {
|
||||
log("Skipping top level LCS");
|
||||
Main.diff(xml1, xml2, out, diffxConfig);
|
||||
out.close();
|
||||
return;
|
||||
}
|
||||
DOMRecorder loader = new DOMRecorder();
|
||||
loader.setConfig(diffxConfig);
|
||||
log("top level LCS - creating EventSequences...");
|
||||
List<EventSequence> leftES = new ArrayList<EventSequence>();
|
||||
for (int i = 0; i < xml1.getChildNodes().getLength(); i++) {
|
||||
if (xml1.getChildNodes().item(i).getNodeType() != 3) {
|
||||
Element e = (Element)xml1.getChildNodes().item(i);
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpc", "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:a14", "http://schemas.microsoft.com/office/drawing/2010/main");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:m", "http://schemas.openxmlformats.org/officeDocument/2006/math");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:mc", "http://schemas.openxmlformats.org/markup-compatibility/2006");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:o", "urn:schemas-microsoft-com:office:office");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:pic", "http://schemas.openxmlformats.org/drawingml/2006/picture");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:v", "urn:schemas-microsoft-com:vml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w10", "urn:schemas-microsoft-com:office:word");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w14", "http://schemas.microsoft.com/office/word/2010/wordml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w15", "http://schemas.microsoft.com/office/word/2012/wordml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wne", "http://schemas.microsoft.com/office/word/2006/wordml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wp", "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wp14", "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpc", "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpg", "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpi", "http://schemas.microsoft.com/office/word/2010/wordprocessingInk");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wps", "http://schemas.microsoft.com/office/word/2010/wordprocessingShape");
|
||||
leftES.add(loader.process(e));
|
||||
}
|
||||
}
|
||||
EventSequenceComparator leftESC = new EventSequenceComparator(leftES);
|
||||
List<EventSequence> rightES = new ArrayList<EventSequence>();
|
||||
for (int j = 0; j < xml2.getChildNodes().getLength(); j++) {
|
||||
if (xml2.getChildNodes().item(j).getNodeType() != 3) {
|
||||
Element e = (Element)xml2.getChildNodes().item(j);
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpc", "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:a14", "http://schemas.microsoft.com/office/drawing/2010/main");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:m", "http://schemas.openxmlformats.org/officeDocument/2006/math");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:mc", "http://schemas.openxmlformats.org/markup-compatibility/2006");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:o", "urn:schemas-microsoft-com:office:office");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:pic", "http://schemas.openxmlformats.org/drawingml/2006/picture");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:v", "urn:schemas-microsoft-com:vml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w10", "urn:schemas-microsoft-com:office:word");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w14", "http://schemas.microsoft.com/office/word/2010/wordml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w15", "http://schemas.microsoft.com/office/word/2012/wordml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wne", "http://schemas.microsoft.com/office/word/2006/wordml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wp", "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wp14", "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpc", "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpg", "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpi", "http://schemas.microsoft.com/office/word/2010/wordprocessingInk");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wps", "http://schemas.microsoft.com/office/word/2010/wordprocessingShape");
|
||||
rightES.add(loader.process(e));
|
||||
}
|
||||
}
|
||||
EventSequenceComparator rightESC = new EventSequenceComparator(rightES);
|
||||
log("top level LCS - determining top level LCS...");
|
||||
RangeDifference[] rd = RangeDifferencer.findDifferences(leftESC, rightESC);
|
||||
SmartXMLFormatter formatter = new SmartXMLFormatter(out);
|
||||
formatter.setConfig(diffxConfig);
|
||||
String rootNodeName = xml1.getNodeName();
|
||||
openResult(rootNodeName, out);
|
||||
if (rd.length == 0) {
|
||||
log("top level LCS done; there are no differences!");
|
||||
addComment("No differences", formatter);
|
||||
for (EventSequence es : leftES)
|
||||
formatEventSequence(es, formatter);
|
||||
closeResult(rootNodeName, out);
|
||||
return;
|
||||
}
|
||||
for (int k = 0; k < rd.length; k++) {
|
||||
RangeDifference rdi = rd[k];
|
||||
log(rdi.kindString() + " left " + rdi.leftStart() + "," + rdi.leftLength() + " right " + rdi.rightStart() + "," + rdi.rightLength());
|
||||
}
|
||||
log("top level LCS done; now performing child actions ...");
|
||||
int leftIdx = 0;
|
||||
for (int m = 0; m < rd.length; m++) {
|
||||
RangeDifference rdi = rd[m];
|
||||
if (rdi.leftStart() > leftIdx) {
|
||||
for (int i2 = leftIdx; i2 < rdi.leftStart(); i2++) {
|
||||
addComment("Adding same", formatter);
|
||||
formatter.declarePrefixMapping(leftESC.getItem(i2).getPrefixMapping());
|
||||
formatEventSequence(leftESC.getItem(i2), formatter);
|
||||
addComment(".. Adding same done ", formatter);
|
||||
}
|
||||
leftIdx = rdi.leftStart();
|
||||
}
|
||||
EventSequence seq1 = new EventSequence();
|
||||
for (int n = rdi.leftStart(); n < rdi.leftEnd(); n++) {
|
||||
if (rdi.kind() == 2) {
|
||||
seq1.addSequence(leftESC.getItem(n));
|
||||
PrefixMapping existingPM = leftESC.getItem(n).getPrefixMapping();
|
||||
addToPrefixMapping(seq1.getPrefixMapping(), existingPM);
|
||||
} else {
|
||||
formatter.declarePrefixMapping(leftESC.getItem(n).getPrefixMapping());
|
||||
addComment("Adding same II", formatter);
|
||||
formatEventSequence(leftESC.getItem(n), formatter);
|
||||
addComment(".. Adding same done", formatter);
|
||||
}
|
||||
}
|
||||
EventSequence seq2 = new EventSequence();
|
||||
for (int i1 = rdi.rightStart(); i1 < rdi.rightEnd(); i1++) {
|
||||
if (rdi.kind() == 2) {
|
||||
seq2.addSequence(rightESC.getItem(i1));
|
||||
PrefixMapping existingPM = rightESC.getItem(i1).getPrefixMapping();
|
||||
addToPrefixMapping(seq2.getPrefixMapping(), existingPM);
|
||||
}
|
||||
}
|
||||
leftIdx = rdi.leftEnd();
|
||||
addComment("Differencing", formatter);
|
||||
if (seq1.size() + seq2.size() < 5000) {
|
||||
mainDiff(seq1, seq2, formatter, diffxConfig);
|
||||
} else {
|
||||
for (int i3 = 0; i3 < seq1.size(); i3++)
|
||||
formatter.delete(seq1.getEvent(i3));
|
||||
for (int i2 = 0; i2 < seq2.size(); i2++)
|
||||
formatter.insert(seq2.getEvent(i2));
|
||||
}
|
||||
addComment(".. Differencing done", formatter);
|
||||
}
|
||||
addComment("Adding tail", formatter);
|
||||
if (rd.length > 0)
|
||||
for (int n = rd[rd.length - 1].leftEnd(); n < leftESC.getRangeCount(); n++)
|
||||
formatEventSequence(leftESC.getItem(n), formatter);
|
||||
closeResult(rootNodeName, out);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
e.printStackTrace();
|
||||
throw new DiffXException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addComment(String message, SmartXMLFormatter formatter) throws IOException {
|
||||
CommentEvent ce = new CommentEvent(message);
|
||||
formatter.format(ce);
|
||||
}
|
||||
|
||||
public static void openResult(String nodename, Writer out) throws IOException {
|
||||
out.append("<" + nodename + " xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"" + " xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\"" + " xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\"" + " xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"" + " xmlns:v=\"urn:schemas-microsoft-com:vml\"" + " xmlns:w10=\"urn:schemas-microsoft-com:office:word\"" + " xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\"" + " xmlns:dfx=\"" + "http://www.topologi.com/2005/Diff-X" + "\"" + " xmlns:del=\"" + "http://www.topologi.com/2005/Diff-X/Delete" + "\"" + " xmlns:ins=\"" + "http://www.topologi.com/2005/Diff-X" + "\"" + " >");
|
||||
}
|
||||
|
||||
public static void closeResult(String nodename, Writer out) throws IOException {
|
||||
out.append("</" + nodename + ">");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Writer diffxResult = new StringWriter();
|
||||
try {
|
||||
long startTime = System.currentTimeMillis();
|
||||
diff(getDocument(new File("1L.xml")).getDocumentElement(), getDocument(new File("1R.xml")).getDocumentElement(), diffxResult);
|
||||
diffxResult.close();
|
||||
long endTime = System.currentTimeMillis();
|
||||
long duration = endTime - startTime;
|
||||
System.out.println(duration + "ms");
|
||||
System.out.println(diffxResult.toString());
|
||||
} catch (Exception exc) {
|
||||
exc.printStackTrace();
|
||||
diffxResult = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Document getDocument(File f) throws Exception {
|
||||
DocumentBuilder db = XmlUtils.getNewDocumentBuilder();
|
||||
return db.parse(f);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package com.topologi.diffx;
|
||||
|
||||
import com.topologi.diffx.algorithm.DiffXAlgorithm;
|
||||
import com.topologi.diffx.algorithm.GuanoAlgorithm;
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
import com.topologi.diffx.config.WhiteSpaceProcessing;
|
||||
import com.topologi.diffx.format.SafeXMLFormatter;
|
||||
import com.topologi.diffx.load.DOMRecorder;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import com.topologi.diffx.sequence.SequenceSlicer;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public final class Extension {
|
||||
private static final Map<String, String> BUILDERS = new Hashtable<String, String>();
|
||||
|
||||
public static Node diff(Node xml1, Node xml2, String whitespace, String granularity) throws DiffXException, IOException {
|
||||
DiffXConfig config = toConfig(whitespace, granularity);
|
||||
DOMRecorder loader = new DOMRecorder();
|
||||
loader.setConfig(config);
|
||||
EventSequence seq1 = loader.process(xml1);
|
||||
EventSequence seq2 = loader.process(xml2);
|
||||
if (seq1.size() == 0 && seq1.size() == 0)
|
||||
return null;
|
||||
StringWriter out = new StringWriter();
|
||||
diff(seq1, seq2, out, config);
|
||||
try {
|
||||
String factory = getFactoryClass(xml1, xml2);
|
||||
Node node = toNode(out.toString(), config, factory);
|
||||
return node;
|
||||
} catch (Exception ex) {
|
||||
throw new DiffXException("Could not generate Node from Diff-X result", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void diff(EventSequence seq1, EventSequence seq2, Writer out, DiffXConfig config) throws DiffXException, IOException {
|
||||
SafeXMLFormatter formatter = new SafeXMLFormatter(out);
|
||||
formatter.declarePrefixMapping(seq1.getPrefixMapping());
|
||||
formatter.declarePrefixMapping(seq2.getPrefixMapping());
|
||||
if (config != null)
|
||||
formatter.setConfig(config);
|
||||
SequenceSlicer slicer = new SequenceSlicer(seq1, seq2);
|
||||
slicer.slice();
|
||||
slicer.formatStart(formatter);
|
||||
DiffXAlgorithm df = new GuanoAlgorithm(seq1, seq2);
|
||||
df.process(formatter);
|
||||
slicer.formatEnd(formatter);
|
||||
}
|
||||
|
||||
private static DiffXConfig toConfig(String whitespace, String granularity) {
|
||||
WhiteSpaceProcessing ws = WhiteSpaceProcessing.valueOf(whitespace);
|
||||
TextGranularity tg = TextGranularity.valueOf(granularity);
|
||||
return new DiffXConfig(ws, tg);
|
||||
}
|
||||
|
||||
private static Node toNode(String xml, DiffXConfig config, String factory) throws IOException, ParserConfigurationException, SAXException {
|
||||
Document document = XmlUtils.getNewDocumentBuilder().parse(new InputSource(new StringReader(xml)));
|
||||
return document.getDocumentElement();
|
||||
}
|
||||
|
||||
private static String getFactoryClass(Node xml1, Node xml2) {
|
||||
Package pkg = (xml1 != null) ? xml1.getClass().getPackage() : ((xml2 != null) ? xml2.getClass().getPackage() : null);
|
||||
return BUILDERS.get(pkg.getName());
|
||||
}
|
||||
}
|
||||
263
rus/WEB-INF/lib/docx4j-3.2.1_src/com/topologi/diffx/Main.java
Normal file
263
rus/WEB-INF/lib/docx4j-3.2.1_src/com/topologi/diffx/Main.java
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
package com.topologi.diffx;
|
||||
|
||||
import com.topologi.diffx.algorithm.DiffXAlgorithm;
|
||||
import com.topologi.diffx.algorithm.DiffXFitWesyma;
|
||||
import com.topologi.diffx.algorithm.DiffXFitopsy;
|
||||
import com.topologi.diffx.algorithm.DiffXFitsy;
|
||||
import com.topologi.diffx.algorithm.DiffXKumarRangan;
|
||||
import com.topologi.diffx.algorithm.GuanoAlgorithm;
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
import com.topologi.diffx.config.WhiteSpaceProcessing;
|
||||
import com.topologi.diffx.format.BasicXMLFormatter;
|
||||
import com.topologi.diffx.format.ConvenientXMLFormatter;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.format.SafeXMLFormatter;
|
||||
import com.topologi.diffx.format.SmartXMLFormatter;
|
||||
import com.topologi.diffx.format.StrictXMLFormatter;
|
||||
import com.topologi.diffx.format.XMLDiffXFormatter;
|
||||
import com.topologi.diffx.load.DOMRecorder;
|
||||
import com.topologi.diffx.load.Recorder;
|
||||
import com.topologi.diffx.load.SAXRecorder;
|
||||
import com.topologi.diffx.load.TextRecorder;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import com.topologi.diffx.sequence.SequenceSlicer;
|
||||
import com.topologi.diffx.util.CommandLine;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
public final class Main {
|
||||
public static boolean equivalent(File xml1, File xml2) throws DiffXException, IOException {
|
||||
Recorder recorder = new SAXRecorder();
|
||||
EventSequence seq0 = recorder.process(xml1);
|
||||
EventSequence seq1 = recorder.process(xml2);
|
||||
return seq0.equals(seq1);
|
||||
}
|
||||
|
||||
public static boolean equivalent(InputStream xml1, InputStream xml2) throws DiffXException, IOException {
|
||||
SAXRecorder recorder = new SAXRecorder();
|
||||
EventSequence seq0 = recorder.process(new InputSource(xml1));
|
||||
EventSequence seq1 = recorder.process(new InputSource(xml2));
|
||||
return seq0.equals(seq1);
|
||||
}
|
||||
|
||||
public static boolean equivalent(Reader xml1, Reader xml2) throws DiffXException, IOException {
|
||||
SAXRecorder recorder = new SAXRecorder();
|
||||
EventSequence seq0 = recorder.process(new InputSource(xml1));
|
||||
EventSequence seq1 = recorder.process(new InputSource(xml2));
|
||||
return seq0.equals(seq1);
|
||||
}
|
||||
|
||||
public static void diff(Node xml1, Node xml2, Writer out, DiffXConfig config) throws DiffXException, IOException {
|
||||
DOMRecorder loader = new DOMRecorder();
|
||||
if (config != null)
|
||||
loader.setConfig(config);
|
||||
EventSequence seq1 = loader.process(xml1);
|
||||
EventSequence seq2 = loader.process(xml2);
|
||||
diff(seq1, seq2, out, config);
|
||||
}
|
||||
|
||||
public static void diff(NodeList xml1, NodeList xml2, Writer out, DiffXConfig config) throws DiffXException, IOException {
|
||||
DOMRecorder loader = new DOMRecorder();
|
||||
if (config != null)
|
||||
loader.setConfig(config);
|
||||
EventSequence seq1 = loader.process(xml1);
|
||||
EventSequence seq2 = loader.process(xml2);
|
||||
diff(seq1, seq2, out, config);
|
||||
}
|
||||
|
||||
public static void diff(Reader xml1, Reader xml2, Writer out, DiffXConfig config) throws DiffXException, IOException {
|
||||
SAXRecorder recorder = new SAXRecorder();
|
||||
if (config != null)
|
||||
recorder.setConfig(config);
|
||||
EventSequence seq1 = recorder.process(new InputSource(xml1));
|
||||
EventSequence seq2 = recorder.process(new InputSource(xml2));
|
||||
diff(seq1, seq2, out, config);
|
||||
}
|
||||
|
||||
public static void diff(Reader xml1, Reader xml2, Writer out) throws DiffXException, IOException {
|
||||
SAXRecorder recorder = new SAXRecorder();
|
||||
EventSequence seq1 = recorder.process(new InputSource(xml1));
|
||||
EventSequence seq2 = recorder.process(new InputSource(xml2));
|
||||
diff(seq1, seq2, out, new DiffXConfig());
|
||||
}
|
||||
|
||||
public static void diff(InputStream xml1, InputStream xml2, OutputStream out) throws DiffXException, IOException {
|
||||
SAXRecorder recorder = new SAXRecorder();
|
||||
EventSequence seq1 = recorder.process(new InputSource(xml1));
|
||||
EventSequence seq2 = recorder.process(new InputSource(xml2));
|
||||
diff(seq1, seq2, new OutputStreamWriter(out), new DiffXConfig());
|
||||
}
|
||||
|
||||
private static void diff(EventSequence seq1, EventSequence seq2, Writer out, DiffXConfig config) throws DiffXException, IOException {
|
||||
SafeXMLFormatter formatter = new SafeXMLFormatter(out);
|
||||
formatter.declarePrefixMapping(seq1.getPrefixMapping());
|
||||
formatter.declarePrefixMapping(seq2.getPrefixMapping());
|
||||
if (config != null)
|
||||
formatter.setConfig(config);
|
||||
SequenceSlicer slicer = new SequenceSlicer(seq1, seq2);
|
||||
slicer.slice();
|
||||
slicer.formatStart(formatter);
|
||||
DiffXAlgorithm df = new GuanoAlgorithm(seq1, seq2);
|
||||
df.process(formatter);
|
||||
slicer.formatEnd(formatter);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length < 2)
|
||||
usage();
|
||||
try {
|
||||
boolean profile = CommandLine.hasSwitch("-profile", args);
|
||||
boolean slice = !CommandLine.hasSwitch("-noslice", args);
|
||||
boolean quiet = CommandLine.hasSwitch("-quiet", args);
|
||||
File xml1 = new File(args[args.length - 2]);
|
||||
File xml2 = new File(args[args.length - 1]);
|
||||
long t0 = System.currentTimeMillis();
|
||||
Recorder recorder = getRecorder(args);
|
||||
EventSequence seq1 = recorder.process(xml1);
|
||||
EventSequence seq2 = recorder.process(xml2);
|
||||
long t1 = System.currentTimeMillis();
|
||||
if (profile)
|
||||
System.err.println("Loaded files in " + (t1 - t0) + "ms");
|
||||
DiffXConfig config = new DiffXConfig();
|
||||
config.setGranularity(getTextGranularity(args));
|
||||
config.setWhiteSpaceProcessing(getWhiteSpaceProcessing(args));
|
||||
if (!quiet)
|
||||
System.err.println("Whitespace processing: " + getTextGranularity(args) + " " + getWhiteSpaceProcessing(args));
|
||||
Writer out = new OutputStreamWriter(getOutput(args), "utf-8");
|
||||
DiffXFormatter formatter = getFormatter(args, out);
|
||||
if (formatter instanceof XMLDiffXFormatter) {
|
||||
((XMLDiffXFormatter)formatter).declarePrefixMapping(seq1.getPrefixMapping());
|
||||
((XMLDiffXFormatter)formatter).declarePrefixMapping(seq2.getPrefixMapping());
|
||||
}
|
||||
formatter.setConfig(config);
|
||||
SequenceSlicer slicer = new SequenceSlicer(seq1, seq2);
|
||||
if (slice) {
|
||||
slicer.slice();
|
||||
slicer.formatStart(formatter);
|
||||
}
|
||||
if (!quiet)
|
||||
System.err.println("Matrix: " + seq1.size() + "x" + seq2.size());
|
||||
DiffXAlgorithm df = getAlgorithm(args, seq1, seq2);
|
||||
df.process(formatter);
|
||||
if (slice)
|
||||
slicer.formatEnd(formatter);
|
||||
long t2 = System.currentTimeMillis();
|
||||
if (profile)
|
||||
System.err.println("Executed algorithm files in " + (t2 - t1) + "ms");
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void usage() {
|
||||
System.err.println("Compare the SAX events returned by two XML files.");
|
||||
System.err.println("usage:");
|
||||
System.err.println(" Main [options] xml_file1 xml_file2");
|
||||
System.err.println("where:");
|
||||
System.err.println(" xml_file1 = Path to the new XML file");
|
||||
System.err.println(" xml_file2 = Path to the old XML file");
|
||||
System.err.println("options:");
|
||||
System.err.println(" -profile Display profiling info");
|
||||
System.err.println(" -noslice Do not use slicing");
|
||||
System.err.println(" -o [output] The output file");
|
||||
System.err.println(" -L [loader] Choose a specific loader");
|
||||
System.err.println(" sax* | dom | text");
|
||||
System.err.println(" -A [algo] Choose a specific algorithm");
|
||||
System.err.println(" fitsy* | guano | fitopsy | kumar | wesyma");
|
||||
System.err.println(" -F [format] Choose a specific formatter");
|
||||
System.err.println(" smart* | basic | convenient | strict | short");
|
||||
System.err.println(" -W [wsp] Define whitespace processing");
|
||||
System.err.println(" preserve* | compare | ignore");
|
||||
System.err.println(" -G [granul] Define text diffing granularity");
|
||||
System.err.println(" word* | text | character");
|
||||
System.err.println(" * indicates option used by default.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private static Recorder getRecorder(String[] args) {
|
||||
String loaderArg = CommandLine.getParameter("-L", args);
|
||||
if (loaderArg == null || "sax".equals(loaderArg))
|
||||
return new SAXRecorder();
|
||||
if ("dom".equals(loaderArg))
|
||||
return new DOMRecorder();
|
||||
if ("text".equals(loaderArg))
|
||||
return new TextRecorder();
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static OutputStream getOutput(String[] args) throws FileNotFoundException {
|
||||
String outArg = CommandLine.getParameter("-o", args);
|
||||
if (outArg == null)
|
||||
return System.out;
|
||||
return new BufferedOutputStream(new FileOutputStream(outArg));
|
||||
}
|
||||
|
||||
private static DiffXAlgorithm getAlgorithm(String[] args, EventSequence seq1, EventSequence seq2) {
|
||||
String loaderArg = CommandLine.getParameter("-A", args);
|
||||
if (loaderArg == null || "fitsy".equals(loaderArg))
|
||||
return new DiffXFitsy(seq1, seq2);
|
||||
if ("guano".equals(loaderArg))
|
||||
return new GuanoAlgorithm(seq1, seq2);
|
||||
if ("fitopsy".equals(loaderArg))
|
||||
return new DiffXFitopsy(seq1, seq2);
|
||||
if ("kumar".equals(loaderArg))
|
||||
return new DiffXKumarRangan(seq1, seq2);
|
||||
if ("wesyma".equals(loaderArg))
|
||||
return new DiffXFitWesyma(seq1, seq2);
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static DiffXFormatter getFormatter(String[] args, Writer out) throws IOException {
|
||||
String formatArg = CommandLine.getParameter("-F", args);
|
||||
if (formatArg == null || "smart".equals(formatArg))
|
||||
return new SmartXMLFormatter(out);
|
||||
if ("convenient".equals(formatArg))
|
||||
return new ConvenientXMLFormatter(out);
|
||||
if ("basic".equals(formatArg))
|
||||
return new BasicXMLFormatter(out);
|
||||
if ("strict".equals(formatArg))
|
||||
return new StrictXMLFormatter(out);
|
||||
if ("short".equals(formatArg))
|
||||
return new StrictXMLFormatter(out);
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static WhiteSpaceProcessing getWhiteSpaceProcessing(String[] args) throws IOException {
|
||||
String formatArg = CommandLine.getParameter("-W", args);
|
||||
if (formatArg == null || "preserve".equals(formatArg))
|
||||
return WhiteSpaceProcessing.PRESERVE;
|
||||
if ("compare".equals(formatArg))
|
||||
return WhiteSpaceProcessing.COMPARE;
|
||||
if ("ignore".equals(formatArg))
|
||||
return WhiteSpaceProcessing.IGNORE;
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static TextGranularity getTextGranularity(String[] args) throws IOException {
|
||||
String formatArg = CommandLine.getParameter("-G", args);
|
||||
if (formatArg == null || "word".equals(formatArg))
|
||||
return TextGranularity.WORD;
|
||||
if ("text".equals(formatArg))
|
||||
return TextGranularity.TEXT;
|
||||
if ("character".equals(formatArg))
|
||||
return TextGranularity.CHARACTER;
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface DiffXAlgorithm {
|
||||
int length();
|
||||
|
||||
void process(DiffXFormatter paramDiffXFormatter) throws IOException;
|
||||
|
||||
EventSequence getFirstSequence();
|
||||
|
||||
EventSequence getSecondSequence();
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
|
||||
public abstract class DiffXAlgorithmBase implements DiffXAlgorithm {
|
||||
protected final EventSequence sequence1;
|
||||
|
||||
protected final EventSequence sequence2;
|
||||
|
||||
protected final int length1;
|
||||
|
||||
protected final int length2;
|
||||
|
||||
protected int length = -1;
|
||||
|
||||
public DiffXAlgorithmBase(EventSequence seq0, EventSequence seq1) {
|
||||
this.sequence1 = seq0;
|
||||
this.sequence2 = seq1;
|
||||
this.length1 = seq0.size();
|
||||
this.length2 = seq1.size();
|
||||
}
|
||||
|
||||
public final EventSequence getFirstSequence() {
|
||||
return this.sequence1;
|
||||
}
|
||||
|
||||
public final EventSequence getSecondSequence() {
|
||||
return this.sequence2;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
public final class DiffXFactory {
|
||||
private static final Class<?>[] ARGS = new Class<?>[] { EventSequence.class, EventSequence.class };
|
||||
|
||||
public static DiffXAlgorithm newAlgorithm(String className, EventSequence sequence1, EventSequence sequence2) throws FactoryException {
|
||||
DiffXAlgorithm algorithm = null;
|
||||
try {
|
||||
Class<DiffXAlgorithm> cls = (Class)Class.forName(className);
|
||||
Constructor<DiffXAlgorithm> cons = cls.getConstructor(ARGS);
|
||||
algorithm = cons.newInstance(sequence1, sequence2);
|
||||
} catch (Exception ex) {
|
||||
throw new FactoryException(ex);
|
||||
}
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static DiffXAlgorithm createDiffex(String className, EventSequence sequence1, EventSequence sequence2) throws FactoryException {
|
||||
return newAlgorithm(className, sequence1, sequence2);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class DiffXFitWesyma extends DiffXAlgorithmBase {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private transient Matrix matrix;
|
||||
|
||||
private transient ElementState estate = new ElementState();
|
||||
|
||||
public DiffXFitWesyma(EventSequence seq0, EventSequence seq1) {
|
||||
super(seq0, seq1);
|
||||
this.matrix = setupMatrix(seq0, seq1);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
this.length = 0;
|
||||
if (this.length < 0) {
|
||||
this.matrix.setup(this.length1 + 1, this.length2 + 1);
|
||||
for (int i = this.length1; i >= 0; i--) {
|
||||
for (int j = this.length2; j >= 0; j--) {
|
||||
if (i >= this.length1 || j >= this.length2) {
|
||||
this.matrix.set(i, j, 0);
|
||||
} else if (this.sequence1.getEvent(i).equals(this.sequence2.getEvent(j))) {
|
||||
this.matrix.incrementPathBy(i, j, maxWeight(this.sequence1.getEvent(i), this.sequence2.getEvent(j)));
|
||||
} else {
|
||||
this.matrix.incrementByMaxPath(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.length = this.matrix.get(0, 0);
|
||||
}
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public void process(DiffXFormatter formatter) throws IOException {
|
||||
processEmpty(formatter);
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
return;
|
||||
length();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
while (i < this.length1 && j < this.length2) {
|
||||
e1 = this.sequence1.getEvent(i);
|
||||
e2 = this.sequence2.getEvent(j);
|
||||
if (e1.equals(e2)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.matrix.isGreaterX(i, j)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (this.matrix.isGreaterY(i, j)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.matrix.isSameXY(i, j)) {
|
||||
boolean priorityInsert = true;
|
||||
if (this.estate.matchCurrent(e1))
|
||||
priorityInsert = true;
|
||||
if (this.estate.matchCurrent(e2))
|
||||
priorityInsert = false;
|
||||
if (e1 instanceof com.topologi.diffx.event.AttributeEvent && !(e2 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
priorityInsert = true;
|
||||
} else if (e2 instanceof com.topologi.diffx.event.AttributeEvent && !(e1 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
priorityInsert = false;
|
||||
}
|
||||
if (priorityInsert) {
|
||||
this.estate.insert(e1);
|
||||
formatter.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
this.estate.delete(e1);
|
||||
formatter.delete(e2);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
while (i < this.length1) {
|
||||
this.estate.insert(this.sequence1.getEvent(i));
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
i++;
|
||||
}
|
||||
while (j < this.length2) {
|
||||
this.estate.delete(this.sequence2.getEvent(j));
|
||||
formatter.delete(this.sequence2.getEvent(j));
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
private void processEmpty(DiffXFormatter formatter) throws IOException {
|
||||
if (this.length1 == 0)
|
||||
for (int i = 0; i < this.length2; i++)
|
||||
formatter.delete(this.sequence2.getEvent(i));
|
||||
if (this.length2 == 0)
|
||||
for (int i = 0; i < this.length1; i++)
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
}
|
||||
|
||||
private static Matrix setupMatrix(EventSequence s1, EventSequence s2) {
|
||||
int max = 0;
|
||||
for (int j = 0; j < s1.size(); j++)
|
||||
max += s1.getEvent(j).getWeight();
|
||||
for (int i = 0; i < s2.size(); i++)
|
||||
max += s2.getEvent(i).getWeight();
|
||||
if (max > 32767)
|
||||
return new MatrixInt();
|
||||
return new MatrixShort();
|
||||
}
|
||||
|
||||
private int maxWeight(DiffXEvent e1, DiffXEvent e2) {
|
||||
return (e1.getWeight() > e2.getWeight()) ? e1.getWeight() : e2.getWeight();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.format.ShortStringFormatter;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class DiffXFitopsy extends DiffXAlgorithmBase {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private transient Matrix matrix;
|
||||
|
||||
private transient ElementState estate = new ElementState();
|
||||
|
||||
public DiffXFitopsy(EventSequence seq0, EventSequence seq1) {
|
||||
super(seq0, seq1);
|
||||
this.matrix = setupMatrix(seq0, seq1);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
this.length = 0;
|
||||
if (this.length < 0) {
|
||||
this.matrix.setup(this.length1 + 1, this.length2 + 1);
|
||||
for (int i = this.length1; i >= 0; i--) {
|
||||
for (int j = this.length2; j >= 0; j--) {
|
||||
if (i >= this.length1 || j >= this.length2) {
|
||||
this.matrix.set(i, j, 0);
|
||||
} else if (this.sequence1.getEvent(i).equals(this.sequence2.getEvent(j))) {
|
||||
this.matrix.incrementPathBy(i, j, 1);
|
||||
} else {
|
||||
this.matrix.incrementByMaxPath(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.length = this.matrix.get(0, 0);
|
||||
}
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public void process(DiffXFormatter formatter) throws IOException {
|
||||
processEmpty(formatter);
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
return;
|
||||
length();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
while (i < this.length1 && j < this.length2) {
|
||||
e1 = this.sequence1.getEvent(i);
|
||||
e2 = this.sequence2.getEvent(j);
|
||||
if (this.matrix.isGreaterX(i, j)) {
|
||||
if (this.estate.okInsert(e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (e1.equals(e2) && this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isGreaterY(i, j)) {
|
||||
if (this.estate.okDelete(e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (e1.equals(e2) && this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okInsert(e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isSameXY(i, j)) {
|
||||
if (e1.equals(e2) && this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okInsert(e1) && (!(e2 instanceof com.topologi.diffx.event.AttributeEvent) || e1 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
this.estate.insert(e1);
|
||||
formatter.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2) && (!(e1 instanceof com.topologi.diffx.event.AttributeEvent) || e2 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while (i < this.length1) {
|
||||
this.estate.insert(this.sequence1.getEvent(i));
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
i++;
|
||||
}
|
||||
while (j < this.length2) {
|
||||
this.estate.delete(this.sequence2.getEvent(j));
|
||||
formatter.delete(this.sequence2.getEvent(j));
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
private void processEmpty(DiffXFormatter formatter) throws IOException {
|
||||
if (this.length1 == 0)
|
||||
for (int i = 0; i < this.length2; i++)
|
||||
formatter.delete(this.sequence2.getEvent(i));
|
||||
if (this.length2 == 0)
|
||||
for (int i = 0; i < this.length1; i++)
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
}
|
||||
|
||||
private static Matrix setupMatrix(EventSequence s1, EventSequence s2) {
|
||||
int max = 0;
|
||||
for (int j = 0; j < s1.size(); j++)
|
||||
max += s1.getEvent(j).getWeight();
|
||||
for (int i = 0; i < s2.size(); i++)
|
||||
max += s2.getEvent(i).getWeight();
|
||||
if (max > 32767)
|
||||
return new MatrixInt();
|
||||
return new MatrixShort();
|
||||
}
|
||||
|
||||
private void printLost(int i, int j) {
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
System.err.println("(!) Ambiguous choice in (" + i + "," + j + ")");
|
||||
System.err.println(" ? +" + ShortStringFormatter.toShortString(e1));
|
||||
System.err.println(" ? -" + ShortStringFormatter.toShortString(e2));
|
||||
System.err.println(" current=" + ShortStringFormatter.toShortString(this.estate.current()));
|
||||
System.err.println(" value in X+1=" + this.matrix.get(i + 1, j));
|
||||
System.err.println(" value in Y+1=" + this.matrix.get(i, j + 1));
|
||||
System.err.println(" equals=" + e1.equals(e2));
|
||||
System.err.println(" greaterX=" + this.matrix.isGreaterX(i, j));
|
||||
System.err.println(" greaterY=" + this.matrix.isGreaterY(i, j));
|
||||
System.err.println(" sameXY=" + this.matrix.isSameXY(i, j));
|
||||
System.err.println(" okFormat1=" + this.estate.okFormat(e1));
|
||||
System.err.println(" okFormat2=" + this.estate.okFormat(e2));
|
||||
System.err.println(" okInsert=" + this.estate.okInsert(e1));
|
||||
System.err.println(" okDelete=" + this.estate.okDelete(e2));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.format.ShortStringFormatter;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class DiffXFitsy extends DiffXAlgorithmBase {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final boolean PROFILE = false;
|
||||
|
||||
private transient Matrix matrix;
|
||||
|
||||
private transient ElementState estate = new ElementState();
|
||||
|
||||
public DiffXFitsy(EventSequence seq0, EventSequence seq1) {
|
||||
super(seq0, seq1);
|
||||
this.matrix = setupMatrix(seq0, seq1);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
this.length = 0;
|
||||
if (this.length < 0) {
|
||||
long t0 = System.currentTimeMillis();
|
||||
this.matrix.setup(this.length1 + 1, this.length2 + 1);
|
||||
long t1 = System.currentTimeMillis();
|
||||
for (int i = this.length1; i >= 0; i--) {
|
||||
for (int j = this.length2; j >= 0; j--) {
|
||||
if (i >= this.length1 || j >= this.length2) {
|
||||
this.matrix.set(i, j, 0);
|
||||
} else if (this.sequence1.getEvent(i).equals(this.sequence2.getEvent(j))) {
|
||||
this.matrix.incrementPathBy(i, j, maxWeight(this.sequence1.getEvent(i), this.sequence2.getEvent(j)));
|
||||
} else {
|
||||
this.matrix.incrementByMaxPath(i, j);
|
||||
}
|
||||
}
|
||||
if (i % (this.length1 / 50) == 0)
|
||||
System.err.println((i * 100 / this.length1) + "% at " + (t1 - System.currentTimeMillis()) + "ms");
|
||||
}
|
||||
this.length = this.matrix.get(0, 0);
|
||||
System.err.println((System.currentTimeMillis() - t1) + " ms to populate");
|
||||
}
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public void process(DiffXFormatter formatter) throws IOException {
|
||||
processEmpty(formatter);
|
||||
System.err.println("Start processing");
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
return;
|
||||
length();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
while (i < this.length1 && j < this.length2) {
|
||||
e1 = this.sequence1.getEvent(i);
|
||||
e2 = this.sequence2.getEvent(j);
|
||||
if (e1.equals(e2)) {
|
||||
if (this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okInsert(e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isGreaterX(i, j)) {
|
||||
if (this.estate.okInsert(e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isGreaterY(i, j)) {
|
||||
if (this.estate.okDelete(e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okInsert(e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isSameXY(i, j)) {
|
||||
if (this.estate.okInsert(e1) && (!(e2 instanceof com.topologi.diffx.event.AttributeEvent) || e1 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
this.estate.insert(e1);
|
||||
formatter.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2) && (!(e1 instanceof com.topologi.diffx.event.AttributeEvent) || e2 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while (i < this.length1) {
|
||||
this.estate.insert(this.sequence1.getEvent(i));
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
i++;
|
||||
}
|
||||
while (j < this.length2) {
|
||||
this.estate.delete(this.sequence2.getEvent(j));
|
||||
formatter.delete(this.sequence2.getEvent(j));
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
private void processEmpty(DiffXFormatter formatter) throws IOException {
|
||||
if (this.length1 == 0)
|
||||
for (int i = 0; i < this.length2; i++)
|
||||
formatter.delete(this.sequence2.getEvent(i));
|
||||
if (this.length2 == 0)
|
||||
for (int i = 0; i < this.length1; i++)
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
}
|
||||
|
||||
private static Matrix setupMatrix(EventSequence s1, EventSequence s2) {
|
||||
int max = 0;
|
||||
for (int j = 0; j < s1.size(); j++)
|
||||
max += s1.getEvent(j).getWeight();
|
||||
for (int i = 0; i < s2.size(); i++)
|
||||
max += s2.getEvent(i).getWeight();
|
||||
if (max > 32767)
|
||||
return new MatrixInt();
|
||||
return new MatrixShort();
|
||||
}
|
||||
|
||||
private int maxWeight(DiffXEvent e1, DiffXEvent e2) {
|
||||
return (e1.getWeight() > e2.getWeight()) ? e1.getWeight() : e2.getWeight();
|
||||
}
|
||||
|
||||
private void printLost(int i, int j) {
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
System.err.println("(!) Ambiguous choice in (" + i + "," + j + ")");
|
||||
System.err.println(" ? +" + ShortStringFormatter.toShortString(e1));
|
||||
System.err.println(" ? -" + ShortStringFormatter.toShortString(e2));
|
||||
System.err.println(" current=" + ShortStringFormatter.toShortString(this.estate.current()));
|
||||
System.err.println(" value in X+1=" + this.matrix.get(i + 1, j));
|
||||
System.err.println(" value in Y+1=" + this.matrix.get(i, j + 1));
|
||||
System.err.println(" equals=" + e1.equals(e2));
|
||||
System.err.println(" greaterX=" + this.matrix.isGreaterX(i, j));
|
||||
System.err.println(" greaterY=" + this.matrix.isGreaterY(i, j));
|
||||
System.err.println(" sameXY=" + this.matrix.isSameXY(i, j));
|
||||
System.err.println(" okFormat1=" + this.estate.okFormat(e1));
|
||||
System.err.println(" okFormat2=" + this.estate.okFormat(e2));
|
||||
System.err.println(" okInsert=" + this.estate.okInsert(e1));
|
||||
System.err.println(" okDelete=" + this.estate.okDelete(e2));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class DiffXKumarRangan extends DiffXAlgorithmBase {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private int[] R1;
|
||||
|
||||
private int[] R2;
|
||||
|
||||
private int[] LL;
|
||||
|
||||
private int[] LL1;
|
||||
|
||||
private int[] LL2;
|
||||
|
||||
private int R;
|
||||
|
||||
private int S;
|
||||
|
||||
private int iSeq2 = 0;
|
||||
|
||||
private int length = -1;
|
||||
|
||||
private DiffXFormatter df = null;
|
||||
|
||||
public DiffXKumarRangan(EventSequence seq0, EventSequence seq1) {
|
||||
super(seq0, seq1);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (this.length < 0)
|
||||
this.length = calculateLength();
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public void process(DiffXFormatter formatter) throws IOException {
|
||||
this.length = calculateLength();
|
||||
this.df = formatter;
|
||||
generateLCS(0, this.length1 - 1, 0, this.length2 - 1, this.length1, this.length2, this.length);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
this.R1 = new int[this.length2 + 1];
|
||||
this.R2 = new int[this.length2 + 1];
|
||||
this.LL = new int[this.length2 + 1];
|
||||
this.LL1 = new int[this.length2 + 1];
|
||||
this.LL2 = new int[this.length2 + 1];
|
||||
this.iSeq2 = 0;
|
||||
}
|
||||
|
||||
private int calculateLength() {
|
||||
init();
|
||||
this.R = 0;
|
||||
this.S = this.length1 + 1;
|
||||
while (this.S > this.R) {
|
||||
this.S--;
|
||||
fillOne(0, this.length1 - 1, 0, this.length2 - 1, this.length1, this.length2, 1);
|
||||
copyUpTo(this.R2, this.R1, this.R);
|
||||
}
|
||||
return this.S;
|
||||
}
|
||||
|
||||
private void fillOne(int start1, int end1, int start2, int end2, int m, int n, int sign) {
|
||||
int j = 1;
|
||||
int i = this.S;
|
||||
boolean over = false;
|
||||
this.R2[0] = n + 1;
|
||||
int lower2 = 0;
|
||||
int position2 = 0;
|
||||
int temp = 0;
|
||||
while (((i > 0) ? true : false) & (!over ? true : false)) {
|
||||
if (j > this.R) {
|
||||
lower2 = 0;
|
||||
} else {
|
||||
lower2 = this.R1[j];
|
||||
}
|
||||
position2 = this.R2[j - 1] - 1;
|
||||
while (position2 > lower2 && !this.sequence1.getEvent((i - 1) * sign + start1).equals(this.sequence2.getEvent((position2 - 1) * sign + start2)))
|
||||
position2--;
|
||||
temp = Math.max(position2, lower2);
|
||||
if (temp == 0) {
|
||||
over = true;
|
||||
continue;
|
||||
}
|
||||
this.R2[j] = temp;
|
||||
i--;
|
||||
j++;
|
||||
}
|
||||
this.R = j - 1;
|
||||
}
|
||||
|
||||
private int[] calMid(int start1, int end1, int start2, int end2, int m, int n, int sign, int waste) {
|
||||
this.LL = new int[n + 1];
|
||||
this.R = 0;
|
||||
for (this.S = m; this.S >= m - waste; this.S--) {
|
||||
fillOne(start1, end1, start2, end2, m, n, sign);
|
||||
copyUpTo(this.R2, this.R1, this.R);
|
||||
}
|
||||
copyUpTo(this.R1, this.LL, this.R);
|
||||
return this.LL;
|
||||
}
|
||||
|
||||
private void generateLCS(int start1, int end1, int start2, int end2, int m, int n, int lcs) throws IOException {
|
||||
if (m - lcs < 2) {
|
||||
getLCSMinimumWaste(start1, end1, start2, end2, m, n, lcs);
|
||||
} else {
|
||||
getLCSMoreWaste(start1, end1, start2, end2, m, n, lcs);
|
||||
}
|
||||
}
|
||||
|
||||
private void getLCSMinimumWaste(int start1, int end1, int start2, int end2, int m, int n, int lcs) throws IOException {
|
||||
int waste = m - lcs;
|
||||
this.LL = calMid(start1, end1, start2, end2, m, n, 1, waste);
|
||||
int i = 0;
|
||||
while (i < lcs && this.sequence1.getEvent(i + start1).equals(this.sequence2.getEvent(this.LL[lcs - i] - 1 + start2))) {
|
||||
this.df.format(this.sequence1.getEvent(i + start1));
|
||||
this.iSeq2++;
|
||||
i++;
|
||||
if (i < lcs)
|
||||
writeDeleted(this.LL[lcs - i] - 1 + start2);
|
||||
}
|
||||
if (i < m)
|
||||
this.df.insert(this.sequence1.getEvent(i + start1));
|
||||
if (i < lcs)
|
||||
writeDeleted(this.LL[lcs - i] - 1 + start2);
|
||||
i++;
|
||||
while (i < m) {
|
||||
this.df.format(this.sequence1.getEvent(i + start1));
|
||||
this.iSeq2++;
|
||||
writeDeleted(this.LL[m - i] - 1 + start2);
|
||||
i++;
|
||||
}
|
||||
writeDeleted(this.LL[0] - 1 + start2);
|
||||
}
|
||||
|
||||
private void getLCSMoreWaste(int start1, int end1, int start2, int end2, int m, int n, int lcs) throws IOException {
|
||||
int waste1 = (int)Math.ceil((double)((float)(m - lcs) / 2.0F));
|
||||
this.LL1 = calMid(end1, start1, end2, start2, m, n, -1, waste1);
|
||||
int r1 = this.R;
|
||||
for (int j = 0; j <= r1; j++)
|
||||
this.LL1[j] = n + 1 - this.LL1[j];
|
||||
int waste2 = (int)Math.floor((double)((float)(m - lcs) / 2.0F));
|
||||
this.LL2 = calMid(start1, end1, start2, end2, m, n, 1, waste2);
|
||||
int r2 = this.R;
|
||||
int k = Math.max(r1, r2);
|
||||
while (k > 0 && (
|
||||
k > r1 || lcs - k > r2 || this.LL1[k] >= this.LL2[lcs - k]))
|
||||
k--;
|
||||
int u = k + waste1;
|
||||
int v = this.LL1[k];
|
||||
generateLCS(start1, start1 + u - 1, start2, start2 + v - 1, u - 1 + 1, v - 1 + 1, u - waste1);
|
||||
generateLCS(start1 + u, end1, start2 + v, end2, end1 - start1 + 1 - u, end2 - start2 + 1 - v, m - u - waste2);
|
||||
}
|
||||
|
||||
private void writeDeleted(int jSeq2) throws IOException {
|
||||
while (jSeq2 > this.iSeq2)
|
||||
this.df.delete(this.sequence2.getEvent(this.iSeq2++));
|
||||
}
|
||||
|
||||
private void printState(int f) {
|
||||
if ((f & 0x1) == 1)
|
||||
System.err.println(" R=" + this.R);
|
||||
if ((f & 0x10) == 16)
|
||||
System.err.println(" S=" + this.S);
|
||||
if ((f & 0x11) > 0)
|
||||
System.err.println();
|
||||
if ((f & 0x100) == 256) {
|
||||
System.err.print(" R1={");
|
||||
for (int element : this.R1)
|
||||
System.err.print(" " + element);
|
||||
System.err.println(" }");
|
||||
}
|
||||
if ((f & 0x1000) == 4096) {
|
||||
System.err.print(" R2={");
|
||||
for (int element : this.R2)
|
||||
System.err.print(" " + element);
|
||||
System.err.println(" }");
|
||||
}
|
||||
if ((f & 0x10000) == 65536) {
|
||||
System.err.print(" LL={");
|
||||
for (int element : this.LL)
|
||||
System.err.print(" " + element);
|
||||
System.err.println(" }");
|
||||
}
|
||||
if ((f & 0x100000) == 1048576) {
|
||||
System.err.print(" LL1={");
|
||||
for (int element : this.LL1)
|
||||
System.err.print(" " + element);
|
||||
System.err.println(" }");
|
||||
}
|
||||
if ((f & 0x1000000) == 16777216) {
|
||||
System.err.print(" LL2={");
|
||||
for (int element : this.LL2)
|
||||
System.err.print(" " + element);
|
||||
System.err.println(" }");
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyUpTo(int[] a, int[] b, int len) {
|
||||
for (int i = 0; i <= len; i++)
|
||||
b[i] = a[i];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
|
||||
public final class ElementState {
|
||||
private transient OpenElementEvent[] openElements;
|
||||
|
||||
private transient char[] openChanges;
|
||||
|
||||
private transient int size;
|
||||
|
||||
public ElementState(int initialCapacity) throws IllegalArgumentException {
|
||||
if (initialCapacity < 0)
|
||||
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
|
||||
this.openElements = new OpenElementEvent[initialCapacity];
|
||||
this.openChanges = new char[initialCapacity];
|
||||
}
|
||||
|
||||
public ElementState() {
|
||||
this(12);
|
||||
}
|
||||
|
||||
public void ensureCapacity(int minCapacity) {
|
||||
int oldCapacity = this.openElements.length;
|
||||
if (minCapacity > oldCapacity) {
|
||||
OpenElementEvent[] oldElements = this.openElements;
|
||||
char[] oldChanges = this.openChanges;
|
||||
int newCapacity = oldCapacity * 3 / 2 + 1;
|
||||
if (newCapacity < minCapacity)
|
||||
newCapacity = minCapacity;
|
||||
this.openElements = new OpenElementEvent[newCapacity];
|
||||
this.openChanges = new char[newCapacity];
|
||||
System.arraycopy(oldElements, 0, this.openElements, 0, this.size);
|
||||
System.arraycopy(oldChanges, 0, this.openChanges, 0, this.size);
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return (this.size == 0);
|
||||
}
|
||||
|
||||
public boolean contains(OpenElementEvent element) {
|
||||
return (indexOf(element) >= 0);
|
||||
}
|
||||
|
||||
public int indexOf(OpenElementEvent element) {
|
||||
if (element == null) {
|
||||
for (int i = 0; i < this.size; i++) {
|
||||
if (this.openElements[i] == null)
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < this.size; i++) {
|
||||
if (element.equals((DiffXEvent)this.openElements[i]))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int lastIndexOf(OpenElementEvent element) {
|
||||
if (element == null) {
|
||||
for (int i = this.size - 1; i >= 0; i--) {
|
||||
if (this.openElements[i] == null)
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
for (int i = this.size - 1; i >= 0; i--) {
|
||||
if (element.equals((DiffXEvent)this.openElements[i]))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public OpenElementEvent current() {
|
||||
if (!isEmpty())
|
||||
return this.openElements[this.size - 1];
|
||||
return null;
|
||||
}
|
||||
|
||||
public char currentChange() {
|
||||
if (!isEmpty())
|
||||
return this.openChanges[this.size - 1];
|
||||
return ' ';
|
||||
}
|
||||
|
||||
public boolean matchCurrent(DiffXEvent e) {
|
||||
if (isEmpty())
|
||||
return false;
|
||||
if (!(e instanceof CloseElementEvent))
|
||||
return false;
|
||||
return ((CloseElementEvent)e).match(current());
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) {
|
||||
if (e instanceof OpenElementEvent) {
|
||||
push((OpenElementEvent)e, '+');
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) {
|
||||
if (e instanceof OpenElementEvent) {
|
||||
push((OpenElementEvent)e, '=');
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) {
|
||||
if (e instanceof OpenElementEvent) {
|
||||
push((OpenElementEvent)e, '-');
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean okFormat(DiffXEvent e) {
|
||||
if (!(e instanceof CloseElementEvent))
|
||||
return true;
|
||||
if (isEmpty())
|
||||
return false;
|
||||
return (((CloseElementEvent)e).match(current()) && this.openChanges[this.size - 1] == '=');
|
||||
}
|
||||
|
||||
public boolean okInsert(DiffXEvent e) {
|
||||
if (!(e instanceof CloseElementEvent))
|
||||
return true;
|
||||
if (isEmpty())
|
||||
return false;
|
||||
return (((CloseElementEvent)e).match(current()) && this.openChanges[this.size - 1] == '+');
|
||||
}
|
||||
|
||||
public boolean okDelete(DiffXEvent e) {
|
||||
if (!(e instanceof CloseElementEvent))
|
||||
return true;
|
||||
if (isEmpty())
|
||||
return false;
|
||||
return (((CloseElementEvent)e).match(current()) && this.openChanges[this.size - 1] == '-');
|
||||
}
|
||||
|
||||
public boolean hasPriorityOver(DiffXEvent e1, DiffXEvent e2) {
|
||||
if (e1 instanceof com.topologi.diffx.event.AttributeEvent && !(e2 instanceof com.topologi.diffx.event.AttributeEvent) && !isEmpty())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void push(OpenElementEvent e, char c) {
|
||||
ensureCapacity(this.size + 1);
|
||||
this.openElements[this.size] = e;
|
||||
this.openChanges[this.size] = c;
|
||||
this.size++;
|
||||
}
|
||||
|
||||
public OpenElementEvent pop() {
|
||||
if (this.size > 0) {
|
||||
this.size--;
|
||||
return this.openElements[this.size];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public OpenElementEvent get(int index) throws IndexOutOfBoundsException {
|
||||
checkRange(index);
|
||||
return this.openElements[index];
|
||||
}
|
||||
|
||||
public OpenElementEvent remove(int index) throws IndexOutOfBoundsException {
|
||||
checkRange(index);
|
||||
OpenElementEvent oldValue = this.openElements[index];
|
||||
int numMoved = this.size - index - 1;
|
||||
if (numMoved > 0)
|
||||
System.arraycopy(this.openElements, index + 1, this.openElements, index, numMoved);
|
||||
this.openElements[--this.size] = null;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
for (int i = 0; i < this.size; i++)
|
||||
this.openElements[i] = null;
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
private void checkRange(int index) throws IndexOutOfBoundsException {
|
||||
if (index >= this.size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.size);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.DiffXException;
|
||||
|
||||
public final class FactoryException extends DiffXException {
|
||||
private static final long serialVersionUID = -4029990831933233646L;
|
||||
|
||||
public FactoryException(Exception ex) {
|
||||
super(ex);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.format.ShortStringFormatter;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class GuanoAlgorithm implements DiffXAlgorithm {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final EventSequence sequence1;
|
||||
|
||||
private final EventSequence sequence2;
|
||||
|
||||
private final int length1;
|
||||
|
||||
private final int length2;
|
||||
|
||||
private transient Matrix matrix;
|
||||
|
||||
private transient ElementState estate = new ElementState();
|
||||
|
||||
private transient int length = -1;
|
||||
|
||||
public GuanoAlgorithm(EventSequence seq0, EventSequence seq1) {
|
||||
this.sequence1 = seq0;
|
||||
this.sequence2 = seq1;
|
||||
this.length1 = seq0.size();
|
||||
this.length2 = seq1.size();
|
||||
this.matrix = setupMatrix(seq0, seq1);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
this.length = 0;
|
||||
if (this.length < 0) {
|
||||
this.matrix.setup(this.length1 + 1, this.length2 + 1);
|
||||
for (int i = this.length1; i >= 0; i--) {
|
||||
for (int j = this.length2; j >= 0; j--) {
|
||||
if (i >= this.length1 || j >= this.length2) {
|
||||
this.matrix.set(i, j, 0);
|
||||
} else if (this.sequence1.getEvent(i).equals(this.sequence2.getEvent(j))) {
|
||||
this.matrix.incrementPathBy(i, j, 1);
|
||||
} else {
|
||||
this.matrix.incrementByMaxPath(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.length = this.matrix.get(0, 0);
|
||||
}
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public void process(DiffXFormatter formatter) throws IOException {
|
||||
processEmpty(formatter);
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
return;
|
||||
length();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
while (i < this.length1 && j < this.length2) {
|
||||
e1 = this.sequence1.getEvent(i);
|
||||
e2 = this.sequence2.getEvent(j);
|
||||
if (this.matrix.isGreaterX(i, j)) {
|
||||
if (this.estate.okInsert(e1) && !this.estate.hasPriorityOver(e2, e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (e1.equals(e2) && this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isGreaterY(i, j)) {
|
||||
if (this.estate.okDelete(e2) && !this.estate.hasPriorityOver(e1, e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (e1.equals(e2) && this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okInsert(e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isSameXY(i, j)) {
|
||||
if (e1.equals(e2) && this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okInsert(e1) && (!(e2 instanceof com.topologi.diffx.event.AttributeEvent) || e1 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
this.estate.insert(e1);
|
||||
formatter.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2) && (!(e1 instanceof com.topologi.diffx.event.AttributeEvent) || e2 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while (i < this.length1) {
|
||||
this.estate.insert(this.sequence1.getEvent(i));
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
i++;
|
||||
}
|
||||
while (j < this.length2) {
|
||||
this.estate.delete(this.sequence2.getEvent(j));
|
||||
formatter.delete(this.sequence2.getEvent(j));
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
public final EventSequence getFirstSequence() {
|
||||
return this.sequence1;
|
||||
}
|
||||
|
||||
public final EventSequence getSecondSequence() {
|
||||
return this.sequence2;
|
||||
}
|
||||
|
||||
private void processEmpty(DiffXFormatter formatter) throws IOException {
|
||||
if (this.length1 == 0)
|
||||
for (int i = 0; i < this.length2; i++)
|
||||
formatter.delete(this.sequence2.getEvent(i));
|
||||
if (this.length2 == 0)
|
||||
for (int i = 0; i < this.length1; i++)
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
}
|
||||
|
||||
private static Matrix setupMatrix(EventSequence s1, EventSequence s2) {
|
||||
int max = 0;
|
||||
for (int j = 0; j < s1.size(); j++)
|
||||
max += s1.getEvent(j).getWeight();
|
||||
for (int i = 0; i < s2.size(); i++)
|
||||
max += s2.getEvent(i).getWeight();
|
||||
if (max > 32767)
|
||||
return new MatrixInt();
|
||||
return new MatrixShort();
|
||||
}
|
||||
|
||||
private void printLost(int i, int j) {
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
System.err.println("(!) Ambiguous choice in (" + i + "," + j + ")");
|
||||
System.err.println(" ? +" + ShortStringFormatter.toShortString(e1));
|
||||
System.err.println(" ? -" + ShortStringFormatter.toShortString(e2));
|
||||
System.err.println(" current=" + ShortStringFormatter.toShortString(this.estate.current()));
|
||||
System.err.println(" value in X+1=" + this.matrix.get(i + 1, j));
|
||||
System.err.println(" value in Y+1=" + this.matrix.get(i, j + 1));
|
||||
System.err.println(" equals=" + e1.equals(e2));
|
||||
System.err.println(" greaterX=" + this.matrix.isGreaterX(i, j));
|
||||
System.err.println(" greaterY=" + this.matrix.isGreaterY(i, j));
|
||||
System.err.println(" sameXY=" + this.matrix.isSameXY(i, j));
|
||||
System.err.println(" okFormat1=" + this.estate.okFormat(e1));
|
||||
System.err.println(" okFormat2=" + this.estate.okFormat(e2));
|
||||
System.err.println(" okInsert=" + this.estate.okInsert(e1));
|
||||
System.err.println(" okDelete=" + this.estate.okDelete(e2));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
public interface Matrix {
|
||||
void setup(int paramInt1, int paramInt2);
|
||||
|
||||
void set(int paramInt1, int paramInt2, int paramInt3);
|
||||
|
||||
int get(int paramInt1, int paramInt2);
|
||||
|
||||
void incrementPathBy(int paramInt1, int paramInt2, int paramInt3);
|
||||
|
||||
void incrementByMaxPath(int paramInt1, int paramInt2);
|
||||
|
||||
boolean isGreaterX(int paramInt1, int paramInt2);
|
||||
|
||||
boolean isGreaterY(int paramInt1, int paramInt2);
|
||||
|
||||
boolean isSameXY(int paramInt1, int paramInt2);
|
||||
|
||||
void release();
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
public final class MatrixInt implements Matrix {
|
||||
private int[][] matrix;
|
||||
|
||||
public void setup(int width, int height) {
|
||||
this.matrix = new int[width][height];
|
||||
}
|
||||
|
||||
public void set(int i, int j, int x) {
|
||||
this.matrix[i][j] = x;
|
||||
}
|
||||
|
||||
public int get(int i, int j) {
|
||||
return this.matrix[i][j];
|
||||
}
|
||||
|
||||
public void incrementPathBy(int i, int j, int n) {
|
||||
this.matrix[i][j] = this.matrix[i + 1][j + 1] + n;
|
||||
}
|
||||
|
||||
public void incrementByMaxPath(int i, int j) {
|
||||
this.matrix[i][j] = Math.max(this.matrix[i + 1][j], this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public boolean isGreaterX(int i, int j) {
|
||||
return (this.matrix[i + 1][j] > this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public boolean isGreaterY(int i, int j) {
|
||||
return (this.matrix[i + 1][j] < this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public boolean isSameXY(int i, int j) {
|
||||
return (this.matrix[i + 1][j] == this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
this.matrix = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
public final class MatrixShort implements Matrix {
|
||||
private short[][] matrix;
|
||||
|
||||
public void setup(int width, int height) {
|
||||
this.matrix = new short[width][height];
|
||||
}
|
||||
|
||||
public void set(int i, int j, int x) {
|
||||
this.matrix[i][j] = (short)x;
|
||||
}
|
||||
|
||||
public int get(int i, int j) {
|
||||
return this.matrix[i][j];
|
||||
}
|
||||
|
||||
public void incrementPathBy(int i, int j, int n) {
|
||||
this.matrix[i][j] = (short)(this.matrix[i + 1][j + 1] + n);
|
||||
}
|
||||
|
||||
public void incrementByMaxPath(int i, int j) {
|
||||
this.matrix[i][j] = max(this.matrix[i + 1][j], this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public boolean isGreaterX(int i, int j) {
|
||||
return (this.matrix[i + 1][j] > this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public boolean isGreaterY(int i, int j) {
|
||||
return (this.matrix[i + 1][j] < this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public boolean isSameXY(int i, int j) {
|
||||
return (this.matrix[i + 1][j] == this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
private static short max(short a, short b) {
|
||||
return (a >= b) ? a : b;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer out = new StringBuffer();
|
||||
for (int j = 0; j < (this.matrix[0]).length; j++) {
|
||||
for (short[] element : this.matrix)
|
||||
out.append(element[j] + "\t");
|
||||
out.append('\n');
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public void release() {
|
||||
this.matrix = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package com.topologi.diffx.config;
|
||||
|
||||
public final class DiffXConfig {
|
||||
private boolean isNamespaceAware = true;
|
||||
|
||||
private boolean reportPrefixDifferences = false;
|
||||
|
||||
private WhiteSpaceProcessing whitespace = WhiteSpaceProcessing.COMPARE;
|
||||
|
||||
private boolean preserveWhiteSpace = true;
|
||||
|
||||
private TextGranularity granularity = TextGranularity.WORD;
|
||||
|
||||
public DiffXConfig() {}
|
||||
|
||||
public DiffXConfig(TextGranularity granularity) {
|
||||
if (granularity == null)
|
||||
throw new NullPointerException("The granularity cannot be configured to be not be null.");
|
||||
this.granularity = granularity;
|
||||
}
|
||||
|
||||
public DiffXConfig(WhiteSpaceProcessing whitespace, TextGranularity granularity) {
|
||||
if (granularity == null)
|
||||
throw new NullPointerException("The granularity cannot be configured to be not be null.");
|
||||
if (whitespace == null)
|
||||
throw new NullPointerException("The whitespace processing cannot be configured to be not be null.");
|
||||
this.granularity = granularity;
|
||||
this.whitespace = whitespace;
|
||||
}
|
||||
|
||||
public void setGranularity(TextGranularity granularity) {
|
||||
if (granularity == null)
|
||||
throw new NullPointerException("The granularity cannot be configured to be not be null.");
|
||||
this.granularity = granularity;
|
||||
}
|
||||
|
||||
public void setWhiteSpaceProcessing(WhiteSpaceProcessing whitespace) {
|
||||
if (whitespace == null)
|
||||
throw new NullPointerException("The whitespace cannot be configured to be not be null.");
|
||||
this.whitespace = whitespace;
|
||||
}
|
||||
|
||||
public void setNamespaceAware(boolean aware) {
|
||||
this.isNamespaceAware = aware;
|
||||
if (!aware)
|
||||
this.reportPrefixDifferences = true;
|
||||
}
|
||||
|
||||
public void setReportPrefixDifferences(boolean report) {
|
||||
this.reportPrefixDifferences = report;
|
||||
if (!report)
|
||||
this.isNamespaceAware = true;
|
||||
}
|
||||
|
||||
public boolean isNamespaceAware() {
|
||||
return this.isNamespaceAware;
|
||||
}
|
||||
|
||||
public boolean isReportPrefixDifferences() {
|
||||
return this.reportPrefixDifferences;
|
||||
}
|
||||
|
||||
public TextGranularity getGranularity() {
|
||||
return this.granularity;
|
||||
}
|
||||
|
||||
public WhiteSpaceProcessing getWhiteSpaceProcessing() {
|
||||
return this.whitespace;
|
||||
}
|
||||
|
||||
public boolean isIgnoreWhiteSpace() {
|
||||
return (this.whitespace != WhiteSpaceProcessing.COMPARE);
|
||||
}
|
||||
|
||||
public boolean isPreserveWhiteSpace() {
|
||||
return this.preserveWhiteSpace;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setIgnoreWhiteSpace(boolean ignore) {
|
||||
if (!ignore) {
|
||||
this.whitespace = WhiteSpaceProcessing.COMPARE;
|
||||
} else {
|
||||
this.whitespace = this.preserveWhiteSpace ? WhiteSpaceProcessing.PRESERVE : WhiteSpaceProcessing.IGNORE;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setPreserveWhiteSpace(boolean preserve) {
|
||||
this.preserveWhiteSpace = preserve;
|
||||
if (this.whitespace != WhiteSpaceProcessing.COMPARE)
|
||||
this.whitespace = preserve ? WhiteSpaceProcessing.PRESERVE : WhiteSpaceProcessing.IGNORE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.topologi.diffx.config;
|
||||
|
||||
public enum TextGranularity {
|
||||
CHARACTER, WORD, TEXT;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.topologi.diffx.config;
|
||||
|
||||
public enum WhiteSpaceProcessing {
|
||||
IGNORE, PRESERVE, COMPARE;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.topologi.diffx.event;
|
||||
|
||||
public interface AttributeEvent extends DiffXEvent {
|
||||
String getName();
|
||||
|
||||
String getValue();
|
||||
|
||||
String getURI();
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.topologi.diffx.event;
|
||||
|
||||
public interface CloseElementEvent extends DiffXEvent {
|
||||
String getName();
|
||||
|
||||
String getURI();
|
||||
|
||||
OpenElementEvent getOpenElement();
|
||||
|
||||
boolean match(OpenElementEvent paramOpenElementEvent);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.topologi.diffx.event;
|
||||
|
||||
import com.topologi.diffx.xml.XMLFormattable;
|
||||
import com.topologi.diffx.xml.XMLWritable;
|
||||
|
||||
public interface DiffXEvent extends XMLWritable, XMLFormattable {
|
||||
boolean equals(DiffXEvent paramDiffXEvent);
|
||||
|
||||
int getWeight();
|
||||
|
||||
void setWeight(int paramInt);
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.topologi.diffx.event;
|
||||
|
||||
public interface OpenElementEvent extends DiffXEvent {
|
||||
String getName();
|
||||
|
||||
String getURI();
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.topologi.diffx.event;
|
||||
|
||||
public interface TextEvent extends DiffXEvent {
|
||||
String getCharacters();
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class AttributeEventImpl extends DiffXEventBase implements AttributeEvent {
|
||||
private final String name;
|
||||
|
||||
private final String value;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public AttributeEventImpl(String name, String value) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Attribute must have a name.");
|
||||
if (value == null)
|
||||
throw new NullPointerException("The attribute value cannot be null, use \"\".");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.hashCode = toHashCode(name, value);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
AttributeEventImpl bae = (AttributeEventImpl)e;
|
||||
return (bae.name.equals(this.name) && bae.value.equals(this.value));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "attribute: " + this.name + "=" + this.value;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.attribute(this.name, this.value);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append(' ');
|
||||
xml.append(this.name);
|
||||
xml.append("=\"");
|
||||
xml.append(ESC.toAttributeValue(this.value));
|
||||
xml.append('"');
|
||||
return xml;
|
||||
}
|
||||
|
||||
private static int toHashCode(String name, String value) {
|
||||
int hash = 23;
|
||||
hash = hash * 37 + ((name != null) ? name.hashCode() : 0);
|
||||
hash = hash * 37 + ((value != null) ? value.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class AttributeEventNSImpl extends DiffXEventBase implements AttributeEvent {
|
||||
private final String uri;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final String value;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public AttributeEventNSImpl(String name, String value) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Attribute must have a name.");
|
||||
if (value == null)
|
||||
throw new NullPointerException("The attribute value cannot be null, use \"\".");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.uri = null;
|
||||
this.hashCode = toHashCode(this.uri, name, value);
|
||||
}
|
||||
|
||||
public AttributeEventNSImpl(String uri, String name, String value) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Attribute must have a name.");
|
||||
if (value == null)
|
||||
throw new NullPointerException("The attribute value cannot be null, use \"\".");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.uri = uri;
|
||||
this.hashCode = toHashCode(uri, name, value);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
AttributeEventNSImpl ae = (AttributeEventNSImpl)e;
|
||||
if (!ae.name.equals(this.name))
|
||||
return false;
|
||||
if (!equals(ae.uri, this.uri))
|
||||
return false;
|
||||
if (!ae.value.equals(this.value))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "attribute: " + this.name + "=" + this.value + " [" + this.uri + "]";
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.attribute(this.uri, this.name, this.value);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append(' ');
|
||||
xml.append(this.name);
|
||||
xml.append("=\"");
|
||||
xml.append(ESC.toAttributeValue(this.value));
|
||||
xml.append('"');
|
||||
return xml;
|
||||
}
|
||||
|
||||
private static boolean equals(String uri1, String uri2) {
|
||||
if (uri1 == null && uri2 == null)
|
||||
return true;
|
||||
if (uri1 == null || uri2 == null)
|
||||
return false;
|
||||
return uri1.equals(uri2);
|
||||
}
|
||||
|
||||
private static int toHashCode(String uri, String name, String value) {
|
||||
int hash = 17;
|
||||
hash = hash * 31 + ((uri != null) ? uri.hashCode() : 0);
|
||||
hash = hash * 31 + ((name != null) ? name.hashCode() : 0);
|
||||
hash = hash * 31 + ((value != null) ? value.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class CharEvent extends DiffXEventBase {
|
||||
public final char c;
|
||||
|
||||
public CharEvent(char c) {
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return 79 + this.c;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
return (this.c == ((CharEvent)e).c);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "char: '" + this.c + '\'';
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.writeText(this.c);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
return xml.append(ESC.toElementText(new char[] { this.c }, 0, 1));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
public final class CharactersEvent extends CharactersEventBase {
|
||||
public CharactersEvent(CharSequence seq) throws NullPointerException {
|
||||
super(seq);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "characters: \"" + getCharacters() + '"';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class CharactersEventBase extends DiffXEventBase implements TextEvent {
|
||||
private final String characters;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public CharactersEventBase(CharSequence seq) throws NullPointerException {
|
||||
if (seq == null)
|
||||
throw new NullPointerException("The characters cannot be null, use \"\"");
|
||||
this.characters = seq.toString();
|
||||
this.hashCode = toHashCode(seq);
|
||||
}
|
||||
|
||||
public final int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public final boolean equals(DiffXEvent e) {
|
||||
if (this == e)
|
||||
return true;
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
CharactersEventBase ce = (CharactersEventBase)e;
|
||||
return ce.characters.equals(this.characters);
|
||||
}
|
||||
|
||||
public final String getCharacters() {
|
||||
return this.characters;
|
||||
}
|
||||
|
||||
public final void toXML(XMLWriter xml) throws IOException {
|
||||
xml.writeText(this.characters);
|
||||
}
|
||||
|
||||
public final StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append(ESC.toElementText(this.characters));
|
||||
return xml;
|
||||
}
|
||||
|
||||
private static int toHashCode(CharSequence s) {
|
||||
return 611 + ((s != null) ? s.hashCode() : 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class CloseElementEventImpl extends DiffXEventBase implements CloseElementEvent {
|
||||
private final OpenElementEvent open;
|
||||
|
||||
public CloseElementEventImpl(String name) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.open = new OpenElementEventImpl(name);
|
||||
}
|
||||
|
||||
public CloseElementEventImpl(OpenElementEvent event) throws NullPointerException {
|
||||
if (event == null)
|
||||
throw new NullPointerException("A close element must correspond to an open element.");
|
||||
this.open = event;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.open.getName();
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public OpenElementEvent getOpenElement() {
|
||||
return this.open;
|
||||
}
|
||||
|
||||
public boolean match(OpenElementEvent event) {
|
||||
if (event == null)
|
||||
return false;
|
||||
if (event == this.open)
|
||||
return true;
|
||||
return event.getName().equals(getName());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return 53 + this.open.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
CloseElementEventImpl ce = (CloseElementEventImpl)e;
|
||||
return ce.getName().equals(getName());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "closeElement: " + getName();
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.closeElement();
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append("</").append(getName()).append('>');
|
||||
return xml;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class CloseElementEventNSImpl extends DiffXEventBase implements CloseElementEvent {
|
||||
private final OpenElementEvent open;
|
||||
|
||||
public CloseElementEventNSImpl(String name) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.open = new OpenElementEventNSImpl(name);
|
||||
}
|
||||
|
||||
public CloseElementEventNSImpl(String uri, String name) throws NullPointerException {
|
||||
if (uri == null)
|
||||
throw new NullPointerException("The URI cannot be null, use \"\".");
|
||||
if (name == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.open = new OpenElementEventNSImpl(uri, name);
|
||||
}
|
||||
|
||||
public CloseElementEventNSImpl(OpenElementEvent event) throws NullPointerException {
|
||||
if (event == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.open = event;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.open.getName();
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return this.open.getURI();
|
||||
}
|
||||
|
||||
public OpenElementEvent getOpenElement() {
|
||||
return this.open;
|
||||
}
|
||||
|
||||
public boolean match(OpenElementEvent event) {
|
||||
if (event == null)
|
||||
return false;
|
||||
if (event == this.open)
|
||||
return true;
|
||||
return (event.getURI().equals(getURI()) && event.getName().equals(getName()));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return 89 + this.open.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
CloseElementEventNSImpl ce = (CloseElementEventNSImpl)e;
|
||||
return (ce.getURI().equals(getURI()) && ce.getName().equals(getName()));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "closeElement: " + getName() + " [" + getURI() + "]";
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.closeElement();
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append("</").append(getName()).append('>');
|
||||
return xml;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class CommentEvent extends DiffXEventBase implements DiffXEvent {
|
||||
private final String comment;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public CommentEvent(String comment) throws NullPointerException {
|
||||
this.comment = comment;
|
||||
this.hashCode = toHashcode(comment);
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return this.comment;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
CommentEvent ce = (CommentEvent)e;
|
||||
return ((ce.comment == null && this.comment == null) || ce.comment.equals(this.comment));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "comment: " + this.comment;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.writeComment(this.comment);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) {
|
||||
xml.append(this.comment);
|
||||
return xml;
|
||||
}
|
||||
|
||||
private int toHashcode(String comment) {
|
||||
return (comment != null) ? (703 + comment.hashCode()) : 703;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.esc.XMLEscape;
|
||||
import com.topologi.diffx.xml.esc.XMLEscapeUTF8;
|
||||
|
||||
abstract class DiffXEventBase implements DiffXEvent {
|
||||
static final XMLEscape ESC = XMLEscapeUTF8.UTF8_ESCAPE;
|
||||
|
||||
int weight = 1;
|
||||
|
||||
public abstract int hashCode();
|
||||
|
||||
public abstract boolean equals(DiffXEvent paramDiffXEvent);
|
||||
|
||||
public final boolean equals(Object o) {
|
||||
if (o == null)
|
||||
return false;
|
||||
if (!(o instanceof DiffXEvent))
|
||||
return false;
|
||||
return equals((DiffXEvent)o);
|
||||
}
|
||||
|
||||
public String toXML() {
|
||||
return toXML(new StringBuffer()).toString();
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return this.weight;
|
||||
}
|
||||
|
||||
public void setWeight(int weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
|
||||
public final class EventFactory {
|
||||
private boolean isNamespaceAware = true;
|
||||
|
||||
public EventFactory() {
|
||||
this.isNamespaceAware = true;
|
||||
}
|
||||
|
||||
public EventFactory(boolean isNamespaceAware) {
|
||||
this.isNamespaceAware = isNamespaceAware;
|
||||
}
|
||||
|
||||
public OpenElementEvent makeOpenElement(String uri, String name) {
|
||||
if (this.isNamespaceAware)
|
||||
return new OpenElementEventNSImpl(uri, name);
|
||||
return new OpenElementEventImpl(name);
|
||||
}
|
||||
|
||||
public OpenElementEvent makeOpenElement(String uri, String localName, String qName) {
|
||||
if (this.isNamespaceAware)
|
||||
return new OpenElementEventNSImpl(uri, localName);
|
||||
return new OpenElementEventImpl(qName);
|
||||
}
|
||||
|
||||
public CloseElementEvent makeCloseElement(OpenElementEvent open) {
|
||||
if (this.isNamespaceAware)
|
||||
return new CloseElementEventNSImpl(open);
|
||||
return new CloseElementEventImpl(open);
|
||||
}
|
||||
|
||||
public AttributeEvent makeAttribute(String uri, String name, String value) {
|
||||
if (this.isNamespaceAware)
|
||||
return new AttributeEventNSImpl("".equals(uri) ? null : uri, name, value);
|
||||
return new AttributeEventImpl(name, value);
|
||||
}
|
||||
|
||||
public AttributeEvent makeAttribute(String uri, String localName, String qName, String value) {
|
||||
if (this.isNamespaceAware)
|
||||
return new AttributeEventNSImpl("".equals(uri) ? null : uri, localName, value);
|
||||
return new AttributeEventImpl(qName, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class IgnorableSpaceEvent implements TextEvent {
|
||||
private final String characters;
|
||||
|
||||
public IgnorableSpaceEvent(CharSequence seq) throws NullPointerException {
|
||||
if (seq == null)
|
||||
throw new NullPointerException("The characters cannot be null, use \"\"");
|
||||
this.characters = seq.toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "ignorable-space";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return 71;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return (o.getClass() == getClass());
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (this == e)
|
||||
return true;
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getCharacters() {
|
||||
return this.characters;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.writeXML(this.characters);
|
||||
}
|
||||
|
||||
public String toXML() {
|
||||
return this.characters;
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append(this.characters);
|
||||
return xml;
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void setWeight(int weight) {}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class LineEvent extends DiffXEventBase implements TextEvent {
|
||||
private final CharSequence characters;
|
||||
|
||||
private final int lineNumber;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public LineEvent(CharSequence line, int lineNumber) throws NullPointerException {
|
||||
if (line == null)
|
||||
throw new NullPointerException("The line cannot be null, use \"\"");
|
||||
this.characters = line;
|
||||
this.lineNumber = lineNumber;
|
||||
this.hashCode = toHashCode(line);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "line:" + this.lineNumber + ": \"" + getCharacters() + '"';
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e == null)
|
||||
return false;
|
||||
if (this == e)
|
||||
return true;
|
||||
if (e.getClass() != LineEvent.class)
|
||||
return false;
|
||||
LineEvent ce = (LineEvent)e;
|
||||
return ce.characters.equals(this.characters);
|
||||
}
|
||||
|
||||
public String getCharacters() {
|
||||
return this.characters.toString();
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return this.lineNumber;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.writeXML(this.characters.toString());
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append(this.characters);
|
||||
return xml;
|
||||
}
|
||||
|
||||
private int toHashCode(CharSequence comment) {
|
||||
return (comment != null) ? (1711 + comment.hashCode()) : 1711;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class OpenElementEventImpl extends DiffXEventBase implements OpenElementEvent {
|
||||
private final String name;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public OpenElementEventImpl(String name) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.name = name;
|
||||
this.hashCode = toHashCode(name);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
OpenElementEventImpl oee = (OpenElementEventImpl)e;
|
||||
return oee.name.equals(this.name);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "openElement: " + this.name;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.openElement(this.name, false);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) {
|
||||
return xml.append('<').append(this.name).append('>');
|
||||
}
|
||||
|
||||
private static int toHashCode(String s) {
|
||||
return 451 + ((s != null) ? s.hashCode() : 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class OpenElementEventNSImpl extends DiffXEventBase implements DiffXEvent, OpenElementEvent {
|
||||
private final String uri;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public OpenElementEventNSImpl(String name) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.uri = "";
|
||||
this.name = name;
|
||||
this.hashCode = toHashCode("", name);
|
||||
}
|
||||
|
||||
public OpenElementEventNSImpl(String uri, String name) throws NullPointerException {
|
||||
if (uri == null)
|
||||
throw new NullPointerException("The URI cannot be null, use \"\".");
|
||||
if (name == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.uri = uri;
|
||||
this.name = name;
|
||||
this.hashCode = toHashCode(uri, name);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e == null)
|
||||
return false;
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
OpenElementEventNSImpl oee = (OpenElementEventNSImpl)e;
|
||||
if (!oee.uri.equals(this.uri))
|
||||
return false;
|
||||
if (!oee.name.equals(this.name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "openElement: " + this.name + " [" + this.uri + "]";
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.openElement(this.uri, this.name, false);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) {
|
||||
return xml.append('<').append(this.name).append('>');
|
||||
}
|
||||
|
||||
private int toHashCode(String uri, String name) {
|
||||
int hash = 107;
|
||||
hash = hash * 13 + ((uri != null) ? uri.hashCode() : 0);
|
||||
hash = hash * 13 + ((name != null) ? name.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class ProcessingInstructionEvent extends DiffXEventBase implements DiffXEvent {
|
||||
private final String target;
|
||||
|
||||
private final String data;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public ProcessingInstructionEvent(String target, String data) throws NullPointerException {
|
||||
this.target = target;
|
||||
this.data = data;
|
||||
this.hashCode = toHashCode(target, data);
|
||||
}
|
||||
|
||||
public String getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
ProcessingInstructionEvent pi = (ProcessingInstructionEvent)e;
|
||||
return (pi.target.equals(this.target) && pi.data.equals(this.data));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "pi: " + this.target + ": " + this.data;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.writePI(this.target, this.data);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append("<?");
|
||||
xml.append(this.target);
|
||||
xml.append(' ');
|
||||
xml.append(this.data);
|
||||
xml.append("?>");
|
||||
return xml;
|
||||
}
|
||||
|
||||
private static int toHashCode(String s1, String s2) {
|
||||
int hash = 7;
|
||||
hash = hash * 103 + ((s1 != null) ? s1.hashCode() : 0);
|
||||
hash = hash * 103 + ((s2 != null) ? s2.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
|
||||
public final class SpaceEvent extends CharactersEventBase implements TextEvent {
|
||||
public static final SpaceEvent SINGLE_WHITESPACE = new SpaceEvent(" ");
|
||||
|
||||
public static final SpaceEvent DOUBLE_WHITESPACE = new SpaceEvent(" ");
|
||||
|
||||
public static final SpaceEvent NEW_LINE = new SpaceEvent("\n");
|
||||
|
||||
public static final SpaceEvent TAB = new SpaceEvent("\t");
|
||||
|
||||
public SpaceEvent(CharSequence w) throws NullPointerException {
|
||||
super(w);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "space: \"" + toString(getCharacters().toCharArray()) + '"';
|
||||
}
|
||||
|
||||
public static SpaceEvent getInstance(CharSequence space) {
|
||||
if (" ".equals(space))
|
||||
return SINGLE_WHITESPACE;
|
||||
if (" ".equals(space))
|
||||
return DOUBLE_WHITESPACE;
|
||||
if ("\n".equals(space))
|
||||
return NEW_LINE;
|
||||
if ("\t".equals(space))
|
||||
return TAB;
|
||||
return new SpaceEvent(space);
|
||||
}
|
||||
|
||||
public static SpaceEvent getInstance(char c) {
|
||||
if (c == ' ')
|
||||
return SINGLE_WHITESPACE;
|
||||
if (c == '\n')
|
||||
return NEW_LINE;
|
||||
if (c == '\t')
|
||||
return TAB;
|
||||
return new SpaceEvent(c + "");
|
||||
}
|
||||
|
||||
private static String toString(char[] chars) {
|
||||
StringBuffer out = new StringBuffer();
|
||||
for (char c : chars) {
|
||||
switch (c) {
|
||||
case '\n':
|
||||
out.append("\\n");
|
||||
break;
|
||||
case '\t':
|
||||
out.append("\\t");
|
||||
break;
|
||||
default:
|
||||
out.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
|
||||
public final class WordEvent extends CharactersEventBase implements TextEvent {
|
||||
public WordEvent(CharSequence w) throws NullPointerException {
|
||||
super(w);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "word: \"" + getCharacters() + '"';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class XMLBranchEvent extends DiffXEventBase implements DiffXEvent {
|
||||
private final DiffXEvent[] branch;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public XMLBranchEvent(DiffXEvent[] events) {
|
||||
this.branch = events;
|
||||
this.hashCode = toHashCode(events);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
if (e.hashCode() != this.hashCode)
|
||||
return false;
|
||||
XMLBranchEvent be = (XMLBranchEvent)e;
|
||||
if (this.branch.length != be.branch.length)
|
||||
return false;
|
||||
for (int i = 0; i < this.branch.length; i++) {
|
||||
if (!be.branch[i].equals(this.branch[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
for (DiffXEvent element : this.branch)
|
||||
element.toXML(xml);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
for (DiffXEvent element : this.branch)
|
||||
element.toXML(xml);
|
||||
return xml;
|
||||
}
|
||||
|
||||
private static int toHashCode(DiffXEvent[] events) {
|
||||
int hash = 17;
|
||||
for (DiffXEvent e : events)
|
||||
hash = hash * 13 + ((e != null) ? e.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.event.impl.ProcessingInstructionEvent;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import com.topologi.diffx.xml.XMLWriterNSImpl;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Stack;
|
||||
|
||||
public final class BasicXMLFormatter implements XMLDiffXFormatter {
|
||||
private final XMLWriter xml;
|
||||
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
private transient boolean writeXMLDeclaration = true;
|
||||
|
||||
private transient boolean isSetup = false;
|
||||
|
||||
private transient short textFormat = 0;
|
||||
|
||||
private transient Stack<AttributeEvent> insAttributes = new Stack<AttributeEvent>();
|
||||
|
||||
private transient Stack<AttributeEvent> delAttributes = new Stack<AttributeEvent>();
|
||||
|
||||
public BasicXMLFormatter(Writer w) throws NullPointerException {
|
||||
if (w == null)
|
||||
throw new NullPointerException("The XML formatter requires a writer");
|
||||
this.xml = new XMLWriterNSImpl(w, false);
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException {
|
||||
if (!this.isSetup)
|
||||
setUpXML();
|
||||
endTextChange();
|
||||
if (!(e instanceof AttributeEvent))
|
||||
flushAttributes();
|
||||
e.toXML(this.xml);
|
||||
if (e instanceof com.topologi.diffx.event.TextEvent &&
|
||||
this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException {
|
||||
change(e, 1);
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException {
|
||||
change(e, -1);
|
||||
}
|
||||
|
||||
private void change(DiffXEvent e, int mod) throws IOException {
|
||||
if (!this.isSetup)
|
||||
setUpXML();
|
||||
if (e instanceof OpenElementEvent) {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
this.xml.openElement((mod > 0) ? "http://www.topologi.com/2005/Diff-X/Insert" : "http://www.topologi.com/2005/Diff-X/Delete", "element", false);
|
||||
this.xml.attribute("name", ((OpenElementEvent)e).getName());
|
||||
this.xml.attribute("ns-uri", ((OpenElementEvent)e).getURI());
|
||||
} else if (e instanceof com.topologi.diffx.event.CloseElementEvent) {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
this.xml.closeElement();
|
||||
} else if (e instanceof com.topologi.diffx.event.TextEvent) {
|
||||
flushAttributes();
|
||||
switchTextChange(mod);
|
||||
e.toXML(this.xml);
|
||||
if (this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
if (mod > 0) {
|
||||
this.insAttributes.push((AttributeEvent)e);
|
||||
} else {
|
||||
this.delAttributes.push((AttributeEvent)e);
|
||||
}
|
||||
} else if (e instanceof ProcessingInstructionEvent) {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
this.xml.openElement((mod > 0) ? "http://www.topologi.com/2005/Diff-X/Insert" : "http://www.topologi.com/2005/Diff-X/Delete", "processing-instruction", false);
|
||||
this.xml.attribute("data", ((ProcessingInstructionEvent)e).getData());
|
||||
this.xml.attribute("target", ((ProcessingInstructionEvent)e).getTarget());
|
||||
} else {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
e.toXML(this.xml);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void setWriteXMLDeclaration(boolean show) {
|
||||
this.writeXMLDeclaration = show;
|
||||
}
|
||||
|
||||
public void declarePrefixMapping(PrefixMapping mapping) {
|
||||
for (Enumeration<String> uris = mapping.getURIs(); uris.hasMoreElements(); ) {
|
||||
String uri = uris.nextElement();
|
||||
this.xml.setPrefixMapping(uri, mapping.getPrefix(uri));
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpXML() throws IOException {
|
||||
if (this.writeXMLDeclaration)
|
||||
this.xml.xmlDecl();
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X/Delete", "del");
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X/Insert", "ins");
|
||||
this.writeXMLDeclaration = false;
|
||||
this.isSetup = true;
|
||||
}
|
||||
|
||||
private void endTextChange() throws IOException {
|
||||
if (this.textFormat != 0) {
|
||||
this.xml.closeElement();
|
||||
this.textFormat = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void switchTextChange(int mod) throws IOException {
|
||||
if (mod > 0) {
|
||||
if (this.textFormat < 0)
|
||||
this.xml.closeElement();
|
||||
if (this.textFormat <= 0) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X/Insert", "text", false);
|
||||
this.textFormat = 1;
|
||||
}
|
||||
} else {
|
||||
if (this.textFormat > 0)
|
||||
this.xml.closeElement();
|
||||
if (this.textFormat >= 0) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X/Delete", "text", false);
|
||||
this.textFormat = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void flushAttributes() throws IOException {
|
||||
flushAttributes(this.insAttributes, "http://www.topologi.com/2005/Diff-X/Insert");
|
||||
flushAttributes(this.delAttributes, "http://www.topologi.com/2005/Diff-X/Delete");
|
||||
}
|
||||
|
||||
private void flushAttributes(Stack<AttributeEvent> atts, String uri) throws IOException {
|
||||
while (!atts.empty()) {
|
||||
AttributeEvent att = atts.pop();
|
||||
this.xml.openElement(uri, "attribute", false);
|
||||
this.xml.attribute("name", att.getName());
|
||||
if (att.getURI() != null)
|
||||
this.xml.attribute("ns-uri", att.getURI());
|
||||
this.xml.attribute("value", att.getValue());
|
||||
this.xml.closeElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import com.topologi.diffx.xml.XMLWriterNSImpl;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Stack;
|
||||
|
||||
public final class ConvenientXMLFormatter implements XMLDiffXFormatter {
|
||||
private final XMLWriter xml;
|
||||
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
private transient boolean writeXMLDeclaration = true;
|
||||
|
||||
private transient boolean isSetup = false;
|
||||
|
||||
private transient short textFormat = 0;
|
||||
|
||||
private transient Stack<AttributeEvent> insAttributes = new Stack<AttributeEvent>();
|
||||
|
||||
private transient Stack<AttributeEvent> delAttributes = new Stack<AttributeEvent>();
|
||||
|
||||
public ConvenientXMLFormatter(Writer w) throws NullPointerException {
|
||||
if (w == null)
|
||||
throw new NullPointerException("The XML formatter requires a writer");
|
||||
this.xml = new XMLWriterNSImpl(w, false);
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException {
|
||||
if (!this.isSetup)
|
||||
setUpXML();
|
||||
endTextChange();
|
||||
if (!(e instanceof AttributeEvent))
|
||||
flushAttributes();
|
||||
e.toXML(this.xml);
|
||||
if (e instanceof com.topologi.diffx.event.TextEvent &&
|
||||
this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException {
|
||||
change(e, 1);
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException {
|
||||
change(e, -1);
|
||||
}
|
||||
|
||||
private void change(DiffXEvent e, int mod) throws IOException {
|
||||
if (!this.isSetup)
|
||||
setUpXML();
|
||||
if (e instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("http://www.topologi.com/2005/Diff-X", (mod > 0) ? "insert" : "delete", "true");
|
||||
} else if (e instanceof com.topologi.diffx.event.CloseElementEvent) {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
this.xml.closeElement();
|
||||
} else if (e instanceof com.topologi.diffx.event.TextEvent) {
|
||||
flushAttributes();
|
||||
switchTextChange(mod);
|
||||
e.toXML(this.xml);
|
||||
if (this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
if (mod > 0) {
|
||||
e.toXML(this.xml);
|
||||
this.insAttributes.push((AttributeEvent)e);
|
||||
} else {
|
||||
this.delAttributes.push((AttributeEvent)e);
|
||||
}
|
||||
} else {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
e.toXML(this.xml);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void setWriteXMLDeclaration(boolean show) {
|
||||
this.writeXMLDeclaration = show;
|
||||
}
|
||||
|
||||
public void declarePrefixMapping(PrefixMapping mapping) {
|
||||
for (Enumeration<String> uris = mapping.getURIs(); uris.hasMoreElements(); ) {
|
||||
String uri = uris.nextElement();
|
||||
this.xml.setPrefixMapping(uri, mapping.getPrefix(uri));
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpXML() throws IOException {
|
||||
if (this.writeXMLDeclaration)
|
||||
this.xml.xmlDecl();
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X", "dfx");
|
||||
this.writeXMLDeclaration = false;
|
||||
this.isSetup = true;
|
||||
}
|
||||
|
||||
private void endTextChange() throws IOException {
|
||||
if (this.textFormat != 0) {
|
||||
this.xml.closeElement();
|
||||
this.textFormat = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void switchTextChange(int mod) throws IOException {
|
||||
if (mod > 0) {
|
||||
if (this.textFormat < 0)
|
||||
this.xml.closeElement();
|
||||
if (this.textFormat <= 0) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", "ins", false);
|
||||
this.textFormat = 1;
|
||||
}
|
||||
} else {
|
||||
if (this.textFormat > 0)
|
||||
this.xml.closeElement();
|
||||
if (this.textFormat >= 0) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", "del", false);
|
||||
this.textFormat = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void flushAttributes() throws IOException {
|
||||
flushAttributes(this.insAttributes, 1);
|
||||
flushAttributes(this.delAttributes, -1);
|
||||
}
|
||||
|
||||
private void flushAttributes(Stack<AttributeEvent> atts, int mod) throws IOException {
|
||||
while (!atts.empty()) {
|
||||
AttributeEvent att = atts.pop();
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", (mod > 0) ? "ins" : "del", false);
|
||||
this.xml.attribute(att.getURI(), att.getName(), att.getValue());
|
||||
this.xml.closeElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface DiffXFormatter {
|
||||
void format(DiffXEvent paramDiffXEvent) throws IOException, IllegalStateException;
|
||||
|
||||
void insert(DiffXEvent paramDiffXEvent) throws IOException, IllegalStateException;
|
||||
|
||||
void delete(DiffXEvent paramDiffXEvent) throws IOException, IllegalStateException;
|
||||
|
||||
void setConfig(DiffXConfig paramDiffXConfig);
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class MultiplexFormatter implements DiffXFormatter {
|
||||
private final List<DiffXFormatter> formatters;
|
||||
|
||||
public MultiplexFormatter() {
|
||||
this.formatters = new ArrayList<DiffXFormatter>();
|
||||
}
|
||||
|
||||
public MultiplexFormatter(DiffXFormatter f) {
|
||||
this.formatters = new ArrayList<DiffXFormatter>(1);
|
||||
this.formatters.add(f);
|
||||
}
|
||||
|
||||
public void add(DiffXFormatter f) {
|
||||
this.formatters.add(f);
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException {
|
||||
for (DiffXFormatter f : this.formatters)
|
||||
f.format(e);
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException {
|
||||
for (DiffXFormatter f : this.formatters)
|
||||
f.insert(e);
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException, IllegalStateException {
|
||||
for (DiffXFormatter f : this.formatters)
|
||||
f.delete(e);
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
for (DiffXFormatter f : this.formatters)
|
||||
f.setConfig(config);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.config.WhiteSpaceProcessing;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.impl.SpaceEvent;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import com.topologi.diffx.xml.XMLWriterNSImpl;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public final class SafeXMLFormatter implements XMLDiffXFormatter {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final XMLWriter xml;
|
||||
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
private transient boolean writeXMLDeclaration = true;
|
||||
|
||||
public SafeXMLFormatter() throws IOException {
|
||||
this(new PrintWriter(System.out));
|
||||
}
|
||||
|
||||
public SafeXMLFormatter(Writer w) throws IOException {
|
||||
this.xml = new XMLWriterNSImpl(w, false);
|
||||
if (this.writeXMLDeclaration) {
|
||||
this.xml.xmlDecl();
|
||||
this.writeXMLDeclaration = false;
|
||||
}
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X", "dfx");
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X/Delete", "del");
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X/Insert", "ins");
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException {
|
||||
e.toXML(this.xml);
|
||||
if (e instanceof com.topologi.diffx.event.impl.CharactersEventBase &&
|
||||
this.config.getWhiteSpaceProcessing() == WhiteSpaceProcessing.IGNORE)
|
||||
this.xml.writeXML(" ");
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException {
|
||||
if (e instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("dfx:insert", "true");
|
||||
} else if (e == SpaceEvent.NEW_LINE) {
|
||||
e.toXML(this.xml);
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharactersEventBase) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", "ins", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
if (this.config.getWhiteSpaceProcessing() == WhiteSpaceProcessing.IGNORE)
|
||||
this.xml.writeXML(" ");
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("ins:" + ((AttributeEvent)e).getName(), "true");
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharEvent) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", "ins", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
} else {
|
||||
e.toXML(this.xml);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException {
|
||||
if (e instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("dfx:delete", "true");
|
||||
} else if (e == SpaceEvent.NEW_LINE) {
|
||||
e.toXML(this.xml);
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharactersEventBase) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", "del", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
if (this.config.getWhiteSpaceProcessing() == WhiteSpaceProcessing.IGNORE)
|
||||
this.xml.writeXML(" ");
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
this.xml.attribute("del:" + ((AttributeEvent)e).getName(), ((AttributeEvent)e).getValue());
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharEvent) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", "del", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
} else {
|
||||
e.toXML(this.xml);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void setWriteXMLDeclaration(boolean show) {
|
||||
this.writeXMLDeclaration = show;
|
||||
}
|
||||
|
||||
public void declarePrefixMapping(PrefixMapping mapping) {
|
||||
for (Enumeration<String> uris = mapping.getURIs(); uris.hasMoreElements(); ) {
|
||||
String uri = uris.nextElement();
|
||||
this.xml.setPrefixMapping(uri, mapping.getPrefix(uri));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.event.impl.CharactersEventBase;
|
||||
import com.topologi.diffx.event.impl.LineEvent;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
public final class ShortStringFormatter implements DiffXFormatter {
|
||||
private final Writer out;
|
||||
|
||||
public ShortStringFormatter() throws IOException {
|
||||
this(new PrintWriter(System.out));
|
||||
}
|
||||
|
||||
public ShortStringFormatter(Writer w) throws IOException {
|
||||
this.out = w;
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException, IllegalStateException {
|
||||
this.out.write(toShortString(e));
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException, IllegalStateException {
|
||||
this.out.write("+");
|
||||
this.out.write(toShortString(e));
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException, IllegalStateException {
|
||||
this.out.write("-");
|
||||
this.out.write(toShortString(e));
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {}
|
||||
|
||||
public static String toShortString(DiffXEvent e) {
|
||||
if (e instanceof OpenElementEvent)
|
||||
return '<' + ((OpenElementEvent)e).getName() + '>';
|
||||
if (e instanceof CloseElementEvent)
|
||||
return "</" + ((CloseElementEvent)e).getName() + '>';
|
||||
if (e instanceof AttributeEvent)
|
||||
return "@" + ((AttributeEvent)e).getName();
|
||||
if (e instanceof com.topologi.diffx.event.impl.WordEvent)
|
||||
return '"' + ((CharactersEventBase)e).getCharacters() + '"';
|
||||
if (e instanceof com.topologi.diffx.event.impl.SpaceEvent)
|
||||
return "_s_";
|
||||
if (e instanceof com.topologi.diffx.event.impl.CharEvent)
|
||||
return '\'' + ((CharactersEventBase)e).getCharacters() + '\'';
|
||||
if (e instanceof com.topologi.diffx.event.impl.IgnorableSpaceEvent)
|
||||
return "_i_";
|
||||
if (e instanceof LineEvent)
|
||||
return "L#" + ((LineEvent)e).getLineNumber();
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.impl.SpaceEvent;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import com.topologi.diffx.xml.XMLWriterNSImpl;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public final class SmartXMLFormatter implements XMLDiffXFormatter {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final XMLWriter xml;
|
||||
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
private transient boolean writeXMLDeclaration = true;
|
||||
|
||||
public SmartXMLFormatter() throws IOException {
|
||||
this(new PrintWriter(System.out));
|
||||
}
|
||||
|
||||
public SmartXMLFormatter(Writer w) throws IOException {
|
||||
this.xml = new XMLWriterNSImpl(w, false);
|
||||
if (this.writeXMLDeclaration) {
|
||||
this.xml.xmlDecl();
|
||||
this.writeXMLDeclaration = false;
|
||||
}
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X", "dfx");
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X/Delete", "del");
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X/Insert", "ins");
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException {
|
||||
e.toXML(this.xml);
|
||||
if (e instanceof com.topologi.diffx.event.impl.CharactersEventBase &&
|
||||
this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException {
|
||||
if (e instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("dfx:insert", "true");
|
||||
} else if (e == SpaceEvent.NEW_LINE) {
|
||||
e.toXML(this.xml);
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharactersEventBase) {
|
||||
this.xml.openElement("ins", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
if (this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("ins:" + ((AttributeEvent)e).getName(), "true");
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharEvent) {
|
||||
this.xml.openElement("ins", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
} else {
|
||||
e.toXML(this.xml);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException {
|
||||
if (e instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("dfx:delete", "true");
|
||||
} else if (e == SpaceEvent.NEW_LINE) {
|
||||
e.toXML(this.xml);
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharactersEventBase) {
|
||||
this.xml.openElement("del", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
if (this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
this.xml.attribute("del:" + ((AttributeEvent)e).getName(), ((AttributeEvent)e).getValue());
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharEvent) {
|
||||
this.xml.openElement("del", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
} else {
|
||||
e.toXML(this.xml);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void setWriteXMLDeclaration(boolean show) {
|
||||
this.writeXMLDeclaration = show;
|
||||
}
|
||||
|
||||
public void declarePrefixMapping(PrefixMapping mapping) {
|
||||
for (Enumeration<String> uris = mapping.getURIs(); uris.hasMoreElements(); ) {
|
||||
String uri = uris.nextElement();
|
||||
this.xml.setPrefixMapping(uri, mapping.getPrefix(uri));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.event.impl.CharEvent;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public final class StrictXMLFormatter implements XMLDiffXFormatter {
|
||||
private final PrintWriter xml;
|
||||
|
||||
private String openDel = "<del>";
|
||||
|
||||
private String closeDel = "</del>";
|
||||
|
||||
private String openIns = "<ins>";
|
||||
|
||||
private String closeIns = "</ins>";
|
||||
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
private transient boolean declareNamespace = true;
|
||||
|
||||
private transient boolean isInserting = false;
|
||||
|
||||
private transient boolean isDeleting = false;
|
||||
|
||||
private transient boolean isElementNude = false;
|
||||
|
||||
public StrictXMLFormatter() {
|
||||
this.xml = new PrintWriter(System.out);
|
||||
init();
|
||||
}
|
||||
|
||||
public StrictXMLFormatter(Writer w) {
|
||||
this.xml = new PrintWriter(w);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
this.xml.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException {
|
||||
if (e instanceof OpenElementEvent) {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isInserting)
|
||||
closeIns();
|
||||
if (this.isDeleting)
|
||||
closeDel();
|
||||
OpenElementEvent oee = (OpenElementEvent)e;
|
||||
this.xml.print('<' + oee.getName());
|
||||
if (this.declareNamespace) {
|
||||
this.xml.print(" xmlns:dfx=\"http://www.topologi.com/2005/Diff-X\"");
|
||||
this.declareNamespace = false;
|
||||
}
|
||||
this.isElementNude = true;
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isInserting)
|
||||
closeIns();
|
||||
if (this.isDeleting)
|
||||
closeDel();
|
||||
this.xml.print(e.toXML());
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
if (this.isElementNude) {
|
||||
this.xml.print(e.toXML());
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot write an attribute once the element is closed");
|
||||
}
|
||||
} else {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isInserting)
|
||||
closeIns();
|
||||
if (this.isDeleting)
|
||||
closeDel();
|
||||
if (e instanceof com.topologi.diffx.event.impl.WordEvent || e instanceof com.topologi.diffx.event.impl.SpaceEvent) {
|
||||
this.xml.print(e.toXML());
|
||||
} else if (e instanceof CharEvent) {
|
||||
this.xml.print(((CharEvent)e).c);
|
||||
}
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException {
|
||||
if (e instanceof OpenElementEvent) {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isDeleting)
|
||||
closeDel();
|
||||
OpenElementEvent oee = (OpenElementEvent)e;
|
||||
this.xml.print('<' + oee.getName());
|
||||
if (this.declareNamespace)
|
||||
this.xml.print(" xmlns:dfx=\"http://www.allette.com.au/diffex\"");
|
||||
this.xml.print(" dfx:insert=\"true\"");
|
||||
this.isElementNude = true;
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isDeleting)
|
||||
closeDel();
|
||||
this.xml.print("</");
|
||||
this.xml.print(((CloseElementEvent)e).getName());
|
||||
this.xml.print('>');
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
if (this.isElementNude) {
|
||||
this.xml.print(" ");
|
||||
this.xml.print(((AttributeEvent)e).getName());
|
||||
this.xml.print("=\"");
|
||||
this.xml.print(((AttributeEvent)e).getValue());
|
||||
this.xml.print('"');
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot insert an attribute once the element is closed");
|
||||
}
|
||||
} else {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isDeleting)
|
||||
closeDel();
|
||||
if (e instanceof com.topologi.diffx.event.impl.WordEvent) {
|
||||
if (!this.isInserting)
|
||||
openIns();
|
||||
this.xml.print(e.toXML());
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.SpaceEvent) {
|
||||
this.xml.print(e.toXML());
|
||||
} else if (e instanceof CharEvent) {
|
||||
this.xml.print(((CharEvent)e).c);
|
||||
}
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException, IllegalStateException {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isInserting)
|
||||
closeIns();
|
||||
if (e instanceof OpenElementEvent) {
|
||||
OpenElementEvent oee = (OpenElementEvent)e;
|
||||
this.xml.print('<' + oee.getName());
|
||||
if (this.declareNamespace)
|
||||
this.xml.print(" xmlns:dfx=\"http://www.allette.com.au/diffex\"");
|
||||
this.xml.print(" dfx:delete=\"true\"");
|
||||
this.xml.print('>');
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
this.xml.print("</");
|
||||
this.xml.print(((CloseElementEvent)e).getName());
|
||||
this.xml.print('>');
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.WordEvent) {
|
||||
if (!this.isDeleting)
|
||||
openDel();
|
||||
this.xml.print(e.toXML());
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.SpaceEvent) {
|
||||
this.xml.print(e.toXML());
|
||||
} else if (e instanceof CharEvent) {
|
||||
this.xml.print(((CharEvent)e).c);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void setInsertTags(String start, String end) throws NullPointerException {
|
||||
if (start == null)
|
||||
throw new NullPointerException("The start element for inserted text must have a value");
|
||||
if (end == null)
|
||||
throw new NullPointerException("The start element for inserted text must have a value");
|
||||
this.openIns = start;
|
||||
this.closeIns = end;
|
||||
}
|
||||
|
||||
public void setDeleteTags(String start, String end) throws NullPointerException {
|
||||
if (start == null)
|
||||
throw new NullPointerException("The start element for deleted text must have a value");
|
||||
if (end == null)
|
||||
throw new NullPointerException("The start element for deleted text must have a value");
|
||||
this.openDel = start;
|
||||
this.closeDel = end;
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void setWriteXMLDeclaration(boolean show) {}
|
||||
|
||||
public void declarePrefixMapping(PrefixMapping mapping) {
|
||||
for (Enumeration<String> uris = mapping.getURIs(); uris.hasMoreElements(); ) {
|
||||
String uri = uris.nextElement();
|
||||
mapping.getPrefix(uri);
|
||||
}
|
||||
}
|
||||
|
||||
private void openIns() {
|
||||
this.xml.print(this.openIns);
|
||||
this.isInserting = true;
|
||||
}
|
||||
|
||||
private void openDel() {
|
||||
this.xml.print(this.openDel);
|
||||
this.isDeleting = true;
|
||||
}
|
||||
|
||||
private void closeIns() {
|
||||
this.xml.print(this.closeIns);
|
||||
this.isInserting = false;
|
||||
}
|
||||
|
||||
private void closeDel() {
|
||||
this.xml.print(this.closeDel);
|
||||
this.isDeleting = false;
|
||||
}
|
||||
|
||||
private void denudeElement() {
|
||||
this.xml.print(">");
|
||||
this.isElementNude = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
|
||||
public interface XMLDiffXFormatter extends DiffXFormatter {
|
||||
void setWriteXMLDeclaration(boolean paramBoolean);
|
||||
|
||||
void declarePrefixMapping(PrefixMapping paramPrefixMapping);
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.impl.AttributeEventImpl;
|
||||
import com.topologi.diffx.event.impl.AttributeEventNSImpl;
|
||||
import java.util.Comparator;
|
||||
|
||||
final class AttributeComparator implements Comparator<AttributeEvent> {
|
||||
public int compare(AttributeEvent o1, AttributeEvent o2) throws ClassCastException {
|
||||
if (o1 instanceof AttributeEventImpl && o2 instanceof AttributeEventImpl)
|
||||
return compare((AttributeEventImpl)o1, (AttributeEventImpl)o2);
|
||||
if (o1 instanceof AttributeEventNSImpl && o2 instanceof AttributeEventNSImpl)
|
||||
return compare((AttributeEventNSImpl)o1, (AttributeEventNSImpl)o2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int compare(AttributeEventImpl att1, AttributeEventImpl att2) {
|
||||
return att1.getName().compareTo(att2.getName());
|
||||
}
|
||||
|
||||
public int compare(AttributeEventNSImpl att1, AttributeEventNSImpl att2) {
|
||||
return toCName(att1).compareTo(toCName(att2));
|
||||
}
|
||||
|
||||
private static String toCName(AttributeEventNSImpl att) {
|
||||
return (att.getURI() != null) ? (att.getURI() + ':' + att.getName()) : att.getName();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.event.impl.EventFactory;
|
||||
import com.topologi.diffx.event.impl.ProcessingInstructionEvent;
|
||||
import com.topologi.diffx.load.text.TextTokenizer;
|
||||
import com.topologi.diffx.load.text.TokenizerFactory;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import org.docx4j.XmlUtils;
|
||||
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 org.w3c.dom.ProcessingInstruction;
|
||||
import org.w3c.dom.Text;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
public final class DOMRecorder implements XMLRecorder {
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
private transient EventFactory efactory;
|
||||
|
||||
private transient TextTokenizer tokenizer;
|
||||
|
||||
private transient EventSequence sequence;
|
||||
|
||||
private transient PrefixMapping mapping;
|
||||
|
||||
private transient int currentWeight = -1;
|
||||
|
||||
private transient List<Integer> weights = new ArrayList<Integer>();
|
||||
|
||||
private transient boolean isFragment = true;
|
||||
|
||||
public DiffXConfig getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public EventSequence process(File file) throws LoadingException, IOException {
|
||||
InputStream in = new BufferedInputStream(new FileInputStream(file));
|
||||
return process(new InputSource(in));
|
||||
}
|
||||
|
||||
public EventSequence process(String xml) throws LoadingException {
|
||||
return process(new InputSource(new StringReader(xml)));
|
||||
}
|
||||
|
||||
public EventSequence process(InputSource is) throws LoadingException {
|
||||
this.isFragment = false;
|
||||
try {
|
||||
DocumentBuilder builder = XmlUtils.getNewDocumentBuilder();
|
||||
Document document = builder.parse(is);
|
||||
return process(document);
|
||||
} catch (Exception ex) {
|
||||
throw new LoadingException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public EventSequence process(Node node) throws LoadingException {
|
||||
this.efactory = new EventFactory(this.config.isNamespaceAware());
|
||||
this.tokenizer = TokenizerFactory.get(this.config);
|
||||
this.sequence = new EventSequence();
|
||||
this.mapping = this.sequence.getPrefixMapping();
|
||||
loadNode(node);
|
||||
this.isFragment = true;
|
||||
return this.sequence;
|
||||
}
|
||||
|
||||
public EventSequence process(NodeList node) throws LoadingException {
|
||||
if (node.getLength() == 0)
|
||||
return new EventSequence();
|
||||
return process(node.item(0));
|
||||
}
|
||||
|
||||
private void loadNode(Node node) throws LoadingException {
|
||||
if (node instanceof Element)
|
||||
load((Element)node);
|
||||
if (node instanceof Text) {
|
||||
load((Text)node);
|
||||
} else if (node instanceof Attr) {
|
||||
load((Attr)node);
|
||||
} else if (node instanceof Document) {
|
||||
load((Document)node);
|
||||
} else if (node instanceof ProcessingInstruction) {
|
||||
load((ProcessingInstruction)node);
|
||||
}
|
||||
}
|
||||
|
||||
private void load(Document document) throws LoadingException {
|
||||
load(document.getDocumentElement());
|
||||
}
|
||||
|
||||
private void load(Element element) throws LoadingException {
|
||||
if (this.currentWeight > 0)
|
||||
this.weights.add(Integer.valueOf(this.currentWeight));
|
||||
this.currentWeight = 1;
|
||||
OpenElementEvent open = null;
|
||||
if (this.config.isNamespaceAware()) {
|
||||
String uri = (element.getNamespaceURI() == null) ? "" : element.getNamespaceURI();
|
||||
String name = element.getLocalName();
|
||||
handlePrefixMapping(uri, element.getPrefix());
|
||||
open = this.efactory.makeOpenElement(uri, name);
|
||||
} else {
|
||||
open = this.efactory.makeOpenElement(null, element.getNodeName());
|
||||
}
|
||||
this.sequence.addEvent(open);
|
||||
NamedNodeMap atts = element.getAttributes();
|
||||
if (atts.getLength() == 1) {
|
||||
load((Attr)atts.item(0));
|
||||
} else if (atts.getLength() > 1) {
|
||||
String[] names = new String[atts.getLength()];
|
||||
for (int j = 0; j < atts.getLength(); j++) {
|
||||
Attr attr = (Attr)atts.item(j);
|
||||
names[j] = attr.getName();
|
||||
}
|
||||
Arrays.sort(names);
|
||||
for (String name : names)
|
||||
load((Attr)atts.getNamedItem(name));
|
||||
}
|
||||
NodeList list = element.getChildNodes();
|
||||
for (int i = 0; i < list.getLength(); i++)
|
||||
loadNode(list.item(i));
|
||||
CloseElementEvent close = this.efactory.makeCloseElement(open);
|
||||
this.sequence.addEvent(close);
|
||||
close.setWeight(this.currentWeight);
|
||||
open.setWeight(this.currentWeight);
|
||||
this.currentWeight += popWeight();
|
||||
}
|
||||
|
||||
private void load(Text text) throws LoadingException {
|
||||
List<TextEvent> events = this.tokenizer.tokenize(text.getData());
|
||||
for (TextEvent e : events)
|
||||
this.sequence.addEvent(e);
|
||||
this.currentWeight += events.size();
|
||||
}
|
||||
|
||||
private void load(ProcessingInstruction pi) throws LoadingException {
|
||||
this.sequence.addEvent(new ProcessingInstructionEvent(pi.getTarget(), pi.getData()));
|
||||
this.currentWeight++;
|
||||
}
|
||||
|
||||
private int popWeight() {
|
||||
if (this.weights.size() > 0)
|
||||
return (Integer)this.weights.remove(this.weights.size() - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void load(Attr attr) {
|
||||
handlePrefixMapping(attr.getNamespaceURI(), attr.getPrefix());
|
||||
load(this.efactory.makeAttribute(attr.getNamespaceURI(), attr.getLocalName(), attr.getNodeName(), attr.getValue()));
|
||||
}
|
||||
|
||||
private void load(AttributeEvent e) {
|
||||
if ("http://www.w3.org/2000/xmlns/".equals(e.getURI())) {
|
||||
this.sequence.mapPrefix(e.getValue(), e.getName());
|
||||
} else {
|
||||
e.setWeight(2);
|
||||
this.currentWeight += 2;
|
||||
this.sequence.addEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePrefixMapping(String uri, String prefix) {
|
||||
if (this.isFragment) {
|
||||
if (this.mapping.getPrefix(uri) != null)
|
||||
return;
|
||||
if (prefix == null && !"".equals(uri)) {
|
||||
this.mapping.add(uri, "");
|
||||
} else if (prefix != null && !"xmlns".equals(prefix)) {
|
||||
this.mapping.add(uri, prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.DiffXException;
|
||||
|
||||
public final class LoadingException extends DiffXException {
|
||||
private static final long serialVersionUID = -5026953481292613087L;
|
||||
|
||||
public LoadingException() {}
|
||||
|
||||
public LoadingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public LoadingException(Exception ex) {
|
||||
super(ex);
|
||||
}
|
||||
|
||||
public LoadingException(String message, Exception ex) {
|
||||
super(message, ex);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Recorder {
|
||||
EventSequence process(File paramFile) throws LoadingException, IOException;
|
||||
|
||||
EventSequence process(String paramString) throws LoadingException, IOException;
|
||||
}
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.event.impl.EventFactory;
|
||||
import com.topologi.diffx.event.impl.ProcessingInstructionEvent;
|
||||
import com.topologi.diffx.load.text.TextTokenizer;
|
||||
import com.topologi.diffx.load.text.TokenizerFactory;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
|
||||
public final class SAXRecorder implements XMLRecorder {
|
||||
private static XMLReader reader;
|
||||
|
||||
private static final String DEFAULT_XML_READER;
|
||||
|
||||
static {
|
||||
String str;
|
||||
try {
|
||||
str = XMLReaderFactory.createXMLReader().getClass().getName();
|
||||
} catch (SAXException ex) {
|
||||
str = "";
|
||||
}
|
||||
DEFAULT_XML_READER = str;
|
||||
}
|
||||
|
||||
private static String readerClassName = DEFAULT_XML_READER;
|
||||
|
||||
private static boolean newReader = true;
|
||||
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
protected transient EventSequence sequence;
|
||||
|
||||
public EventSequence process(File file) throws LoadingException, IOException {
|
||||
InputStream in = new BufferedInputStream(new FileInputStream(file));
|
||||
EventSequence seq = null;
|
||||
seq = process(new InputSource(in));
|
||||
in.close();
|
||||
in = null;
|
||||
return seq;
|
||||
}
|
||||
|
||||
public EventSequence process(String xml) throws LoadingException, IOException {
|
||||
return process(new InputSource(new StringReader(xml)));
|
||||
}
|
||||
|
||||
public EventSequence process(InputSource is) throws LoadingException, IOException {
|
||||
if (reader == null || newReader)
|
||||
init();
|
||||
reader.setContentHandler(new RecorderHandler());
|
||||
reader.setErrorHandler(new RecorderErrorHandler());
|
||||
try {
|
||||
reader.setFeature("http://xml.org/sax/features/namespaces", this.config.isNamespaceAware());
|
||||
reader.setFeature("http://xml.org/sax/features/namespace-prefixes", this.config.isReportPrefixDifferences());
|
||||
reader.parse(is);
|
||||
} catch (SAXException ex) {
|
||||
throw new LoadingException(ex);
|
||||
}
|
||||
return this.sequence;
|
||||
}
|
||||
|
||||
public DiffXConfig getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public static String getXMLReaderClass() {
|
||||
return readerClassName;
|
||||
}
|
||||
|
||||
public static void setXMLReaderClass(String className) {
|
||||
if (className == null)
|
||||
className = DEFAULT_XML_READER;
|
||||
newReader = !className.equals(readerClassName);
|
||||
readerClassName = className;
|
||||
}
|
||||
|
||||
private static void init() throws LoadingException {
|
||||
try {
|
||||
reader = XMLReaderFactory.createXMLReader(readerClassName);
|
||||
reader.setFeature("http://xml.org/sax/features/validation", false);
|
||||
} catch (SAXException ex) {
|
||||
throw new LoadingException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private final class RecorderHandler extends DefaultHandler {
|
||||
private final StringBuffer ch = new StringBuffer();
|
||||
|
||||
private final AttributeComparator comparator = new AttributeComparator();
|
||||
|
||||
private transient int currentWeight = -1;
|
||||
|
||||
private transient List<OpenElementEvent> openElements = new ArrayList<OpenElementEvent>();
|
||||
|
||||
private transient List<Integer> weights = new ArrayList<Integer>();
|
||||
|
||||
private transient EventFactory efactory;
|
||||
|
||||
private transient TextTokenizer tokenizer;
|
||||
|
||||
public void startDocument() {
|
||||
SAXRecorder.this.sequence = new EventSequence();
|
||||
this.efactory = new EventFactory(SAXRecorder.this.config.isNamespaceAware());
|
||||
this.tokenizer = TokenizerFactory.get(SAXRecorder.this.config);
|
||||
SAXRecorder.this.sequence.mapPrefix("http://www.w3.org/XML/1998/namespace", "xml");
|
||||
}
|
||||
|
||||
public void startPrefixMapping(String prefix, String uri) throws SAXException {
|
||||
SAXRecorder.this.sequence.mapPrefix(uri, prefix);
|
||||
}
|
||||
|
||||
public void startElement(String uri, String localName, String qName, Attributes atts) {
|
||||
recordCharacters();
|
||||
if (this.currentWeight > 0)
|
||||
this.weights.add(new Integer(this.currentWeight));
|
||||
this.currentWeight = 1;
|
||||
OpenElementEvent open = this.efactory.makeOpenElement(uri, localName, qName);
|
||||
this.openElements.add(open);
|
||||
SAXRecorder.this.sequence.addEvent(open);
|
||||
handleAttributes(atts);
|
||||
}
|
||||
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
recordCharacters();
|
||||
OpenElementEvent open = popLastOpenElement();
|
||||
open.setWeight(this.currentWeight);
|
||||
CloseElementEvent close = this.efactory.makeCloseElement(open);
|
||||
close.setWeight(this.currentWeight);
|
||||
SAXRecorder.this.sequence.addEvent(close);
|
||||
this.currentWeight += popWeight();
|
||||
}
|
||||
|
||||
public void characters(char[] buf, int pos, int len) {
|
||||
this.ch.append(buf, pos, len);
|
||||
}
|
||||
|
||||
public void ignorableWhitespace(char[] buf1, int pos, int len) {}
|
||||
|
||||
public void processingInstruction(String target, String data) {
|
||||
SAXRecorder.this.sequence.addEvent(new ProcessingInstructionEvent(target, data));
|
||||
this.currentWeight++;
|
||||
}
|
||||
|
||||
public void endDocument() throws SAXException {}
|
||||
|
||||
private void recordCharacters() {
|
||||
if (this.ch != null) {
|
||||
List<TextEvent> events = this.tokenizer.tokenize(this.ch);
|
||||
for (TextEvent e : events)
|
||||
SAXRecorder.this.sequence.addEvent(e);
|
||||
this.currentWeight += events.size();
|
||||
this.ch.setLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
private OpenElementEvent popLastOpenElement() {
|
||||
return (OpenElementEvent)this.openElements.remove(this.openElements.size() - 1);
|
||||
}
|
||||
|
||||
private int popWeight() {
|
||||
if (this.weights.size() > 0)
|
||||
return (Integer)this.weights.remove(this.weights.size() - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void handleAttributes(Attributes atts) {
|
||||
if (atts.getLength() == 1) {
|
||||
SAXRecorder.this.sequence.addEvent(this.efactory.makeAttribute(atts.getURI(0), atts.getLocalName(0), atts.getQName(0), atts.getValue(0)));
|
||||
} else if (atts.getLength() > 1) {
|
||||
AttributeEvent[] attEvents = new AttributeEvent[atts.getLength()];
|
||||
for (int i = 0; i < atts.getLength(); i++) {
|
||||
attEvents[i] = this.efactory.makeAttribute(atts.getURI(i), atts.getLocalName(i), atts.getQName(i), atts.getValue(i));
|
||||
attEvents[i].setWeight(2);
|
||||
this.currentWeight += 2;
|
||||
}
|
||||
Arrays.<AttributeEvent>sort(attEvents, this.comparator);
|
||||
for (AttributeEvent attEvent : attEvents)
|
||||
SAXRecorder.this.sequence.addEvent(attEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private RecorderHandler() {}
|
||||
}
|
||||
|
||||
private static final class RecorderErrorHandler implements ErrorHandler {
|
||||
private RecorderErrorHandler() {}
|
||||
|
||||
public void error(SAXParseException ex) throws SAXException {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
public void fatalError(SAXParseException ex) throws SAXException {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
public void warning(SAXParseException ex) throws SAXException {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.event.impl.LineEvent;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
|
||||
public final class TextRecorder implements Recorder {
|
||||
public EventSequence process(File file) throws LoadingException, IOException {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(file));
|
||||
String line = reader.readLine();
|
||||
int count = 0;
|
||||
EventSequence seq = new EventSequence();
|
||||
while (line != null) {
|
||||
seq.addEvent(new LineEvent(line, ++count));
|
||||
line = reader.readLine();
|
||||
}
|
||||
reader.close();
|
||||
return seq;
|
||||
}
|
||||
|
||||
public EventSequence process(String text) throws LoadingException, IOException {
|
||||
BufferedReader reader = new BufferedReader(new StringReader(text));
|
||||
String line = reader.readLine();
|
||||
int count = 0;
|
||||
EventSequence seq = new EventSequence();
|
||||
while (line != null) {
|
||||
seq.addEvent(new LineEvent(line, ++count));
|
||||
line = reader.readLine();
|
||||
}
|
||||
return seq;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
public interface XMLRecorder extends Recorder {
|
||||
EventSequence process(InputSource paramInputSource) throws LoadingException, IOException;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.topologi.diffx.load.text;
|
||||
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import java.util.List;
|
||||
|
||||
public interface TextTokenizer {
|
||||
List<TextEvent> tokenize(CharSequence paramCharSequence);
|
||||
|
||||
TextGranularity granurality();
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.topologi.diffx.load.text;
|
||||
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.event.impl.CharactersEvent;
|
||||
import com.topologi.diffx.event.impl.SpaceEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class TokenizerByChar implements TextTokenizer {
|
||||
private final Map<Character, TextEvent> recycling = new HashMap<Character, TextEvent>();
|
||||
|
||||
public List<TextEvent> tokenize(CharSequence seq) {
|
||||
if (seq == null)
|
||||
return null;
|
||||
if (seq.length() == 0)
|
||||
return Collections.<TextEvent>emptyList();
|
||||
List<TextEvent> events = new ArrayList<TextEvent>(seq.length());
|
||||
Character c = null;
|
||||
for (int i = 0; i < seq.length(); i++) {
|
||||
c = seq.charAt(i);
|
||||
TextEvent e = this.recycling.get(c);
|
||||
if (e == null)
|
||||
if (Character.isWhitespace(c.charValue())) {
|
||||
e = SpaceEvent.getInstance(c.charValue());
|
||||
} else {
|
||||
e = new CharactersEvent(c + "");
|
||||
}
|
||||
events.add(e);
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
public TextGranularity granurality() {
|
||||
return TextGranularity.CHARACTER;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package com.topologi.diffx.load.text;
|
||||
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
import com.topologi.diffx.config.WhiteSpaceProcessing;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.event.impl.CharactersEvent;
|
||||
import com.topologi.diffx.event.impl.IgnorableSpaceEvent;
|
||||
import com.topologi.diffx.event.impl.SpaceEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public final class TokenizerByText implements TextTokenizer {
|
||||
private final WhiteSpaceProcessing whitespace;
|
||||
|
||||
public TokenizerByText(WhiteSpaceProcessing whitespace) {
|
||||
if (whitespace == null)
|
||||
throw new NullPointerException("the white space processing must be specified.");
|
||||
this.whitespace = whitespace;
|
||||
}
|
||||
|
||||
public List<TextEvent> tokenize(CharSequence seq) {
|
||||
TextEvent e;
|
||||
if (seq == null)
|
||||
return null;
|
||||
if (seq.length() == 0)
|
||||
return Collections.<TextEvent>emptyList();
|
||||
int x = TokenizerUtils.getLeadingWhiteSpace(seq);
|
||||
int y = TokenizerUtils.getTrailingWhiteSpace(seq);
|
||||
if (x == 0 && y == 0) {
|
||||
TextEvent textEvent = new CharactersEvent(seq);
|
||||
return Collections.<TextEvent>singletonList(textEvent);
|
||||
}
|
||||
if (x == seq.length()) {
|
||||
switch (this.whitespace) {
|
||||
case COMPARE:
|
||||
return Collections.<TextEvent>singletonList(SpaceEvent.getInstance(seq.toString()));
|
||||
case PRESERVE:
|
||||
return Collections.<TextEvent>singletonList(new IgnorableSpaceEvent(seq.toString()));
|
||||
case IGNORE:
|
||||
return Collections.<TextEvent>emptyList();
|
||||
}
|
||||
TextEvent textEvent = new CharactersEvent(seq);
|
||||
return Collections.<TextEvent>singletonList(textEvent);
|
||||
}
|
||||
List<TextEvent> events = null;
|
||||
switch (this.whitespace) {
|
||||
case COMPARE:
|
||||
events = new ArrayList<TextEvent>(1 + ((x > 0) ? 1 : 0) + ((y > 0) ? 1 : 0));
|
||||
if (x > 0)
|
||||
events.add(SpaceEvent.getInstance(seq.subSequence(0, x)));
|
||||
events.add(new CharactersEvent(seq.subSequence(x, seq.length() - y)));
|
||||
if (y > 0)
|
||||
events.add(SpaceEvent.getInstance(seq.subSequence(seq.length() - y, seq.length())));
|
||||
break;
|
||||
case PRESERVE:
|
||||
events = new ArrayList<TextEvent>(1 + ((x > 0) ? 1 : 0) + ((y > 0) ? 1 : 0));
|
||||
if (x > 0)
|
||||
events.add(new IgnorableSpaceEvent(seq.subSequence(0, x)));
|
||||
events.add(new CharactersEvent(seq.subSequence(x, seq.length() - y)));
|
||||
if (y > 0)
|
||||
events.add(new IgnorableSpaceEvent(seq.subSequence(seq.length() - y, seq.length())));
|
||||
break;
|
||||
case IGNORE:
|
||||
e = new CharactersEvent(seq.subSequence(x, seq.length() - y));
|
||||
events = Collections.<TextEvent>singletonList(e);
|
||||
break;
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
public TextGranularity granurality() {
|
||||
return TextGranularity.TEXT;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package com.topologi.diffx.load.text;
|
||||
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
import com.topologi.diffx.config.WhiteSpaceProcessing;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.event.impl.IgnorableSpaceEvent;
|
||||
import com.topologi.diffx.event.impl.SpaceEvent;
|
||||
import com.topologi.diffx.event.impl.WordEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class TokenizerByWord implements TextTokenizer {
|
||||
private final Map<String, TextEvent> recycling = new HashMap<String, TextEvent>();
|
||||
|
||||
private final WhiteSpaceProcessing whitespace;
|
||||
|
||||
public TokenizerByWord(WhiteSpaceProcessing whitespace) {
|
||||
if (whitespace == null)
|
||||
throw new NullPointerException("the white space processing must be specified.");
|
||||
this.whitespace = whitespace;
|
||||
}
|
||||
|
||||
public List<TextEvent> tokenize(CharSequence seq) {
|
||||
if (seq == null)
|
||||
return null;
|
||||
if (seq.length() == 0)
|
||||
return Collections.<TextEvent>emptyList();
|
||||
List<TextEvent> events = new ArrayList<TextEvent>(seq.length());
|
||||
Pattern p = Pattern.compile("\\s+");
|
||||
Matcher m = p.matcher(seq);
|
||||
int index = 0;
|
||||
while (m.find()) {
|
||||
if (index != m.start()) {
|
||||
String word = seq.subSequence(index, m.start()).toString();
|
||||
events.add(getWordEvent(word));
|
||||
}
|
||||
if (this.whitespace != WhiteSpaceProcessing.IGNORE) {
|
||||
String space = seq.subSequence(m.start(), m.end()).toString();
|
||||
events.add(getSpaceEvent(space));
|
||||
}
|
||||
index = m.end();
|
||||
}
|
||||
if (index != seq.length()) {
|
||||
String word = seq.subSequence(index, seq.length()).toString();
|
||||
events.add(getWordEvent(word));
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
public TextGranularity granurality() {
|
||||
return TextGranularity.WORD;
|
||||
}
|
||||
|
||||
private TextEvent getWordEvent(String word) {
|
||||
TextEvent e = this.recycling.get(word);
|
||||
if (e == null) {
|
||||
e = new WordEvent(word);
|
||||
this.recycling.put(word, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
private TextEvent getSpaceEvent(String space) {
|
||||
TextEvent e = this.recycling.get(space);
|
||||
if (e == null) {
|
||||
if (this.whitespace == WhiteSpaceProcessing.PRESERVE) {
|
||||
e = new IgnorableSpaceEvent(space);
|
||||
} else {
|
||||
e = SpaceEvent.getInstance(space);
|
||||
}
|
||||
this.recycling.put(space, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.topologi.diffx.load.text;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
|
||||
public final class TokenizerFactory {
|
||||
public static TextTokenizer get(DiffXConfig config) {
|
||||
if (config == null)
|
||||
throw new NullPointerException("The config should be specified");
|
||||
TextGranularity granularity = config.getGranularity();
|
||||
switch (granularity) {
|
||||
case CHARACTER:
|
||||
return new TokenizerByChar();
|
||||
case WORD:
|
||||
return new TokenizerByWord(config.getWhiteSpaceProcessing());
|
||||
case TEXT:
|
||||
return new TokenizerByText(config.getWhiteSpaceProcessing());
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported text granularity " + granularity);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.topologi.diffx.load.text;
|
||||
|
||||
final class TokenizerUtils {
|
||||
public static int getLeadingWhiteSpace(CharSequence s) {
|
||||
int i = 0;
|
||||
if (0 == s.length())
|
||||
return 0;
|
||||
char c = s.charAt(0);
|
||||
i++;
|
||||
while ((c == ' ' || c == '\t' || c == '\n') && i != s.length())
|
||||
c = s.charAt(i);
|
||||
return i;
|
||||
}
|
||||
|
||||
public static int getTrailingWhiteSpace(CharSequence s) {
|
||||
int i = 0;
|
||||
if (s.length() == 0)
|
||||
return 0;
|
||||
char c = s.charAt(s.length() - 1 - i);
|
||||
i++;
|
||||
while ((c == ' ' || c == '\t' || c == '\n') && i != s.length())
|
||||
c = s.charAt(s.length() - 1 - i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
package com.topologi.diffx.sequence;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public final class EventSequence {
|
||||
private final PrefixMapping prefixMapping = new PrefixMapping();
|
||||
|
||||
private final List<DiffXEvent> sequence;
|
||||
|
||||
public EventSequence() {
|
||||
this.sequence = new LinkedList<DiffXEvent>();
|
||||
}
|
||||
|
||||
public EventSequence(int size) {
|
||||
this.sequence = new ArrayList<DiffXEvent>(size);
|
||||
}
|
||||
|
||||
public void addSequence(EventSequence seq) {
|
||||
for (int i = 0; i < seq.size(); i++)
|
||||
this.sequence.add(seq.getEvent(i));
|
||||
}
|
||||
|
||||
public void addEvent(DiffXEvent e) {
|
||||
this.sequence.add(e);
|
||||
}
|
||||
|
||||
public void addEvent(int i, DiffXEvent e) {
|
||||
this.sequence.add(i, e);
|
||||
}
|
||||
|
||||
public DiffXEvent getEvent(int i) {
|
||||
return this.sequence.get(i);
|
||||
}
|
||||
|
||||
public DiffXEvent setEvent(int index, DiffXEvent e) {
|
||||
return this.sequence.set(index, e);
|
||||
}
|
||||
|
||||
public DiffXEvent removeEvent(int index) {
|
||||
return (DiffXEvent)this.sequence.remove(index);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.sequence.size();
|
||||
}
|
||||
|
||||
public EventIterator eventIterator() {
|
||||
return new EventIterator(this.sequence.iterator());
|
||||
}
|
||||
|
||||
public List<DiffXEvent> events() {
|
||||
return this.sequence;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.sequence.size();
|
||||
}
|
||||
|
||||
public boolean equals(EventSequence seq) {
|
||||
if (seq == null)
|
||||
return false;
|
||||
if (seq.getClass() != getClass())
|
||||
return false;
|
||||
List<DiffXEvent> sequence2 = seq.sequence;
|
||||
if (this.sequence.size() != this.sequence.size())
|
||||
return false;
|
||||
DiffXEvent x1 = null;
|
||||
DiffXEvent x2 = null;
|
||||
for (int i = 0; i < this.sequence.size(); i++) {
|
||||
x1 = this.sequence.get(i);
|
||||
x2 = sequence2.get(i);
|
||||
if (!x1.equals(x2))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof EventSequence))
|
||||
return false;
|
||||
return equals((EventSequence)o);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Event Sequence [" + size() + "]";
|
||||
}
|
||||
|
||||
public void export(PrintWriter w) {
|
||||
DiffXEvent x = null;
|
||||
for (int i = 0; i < this.sequence.size(); i++) {
|
||||
x = this.sequence.get(i);
|
||||
w.println(x.toString());
|
||||
}
|
||||
w.flush();
|
||||
}
|
||||
|
||||
public void mapPrefix(String uri, String prefix) throws NullPointerException {
|
||||
this.prefixMapping.add(uri, prefix);
|
||||
}
|
||||
|
||||
public PrefixMapping getPrefixMapping() {
|
||||
return this.prefixMapping;
|
||||
}
|
||||
|
||||
public final class EventIterator implements Iterator<DiffXEvent> {
|
||||
private final Iterator<DiffXEvent> iterator;
|
||||
|
||||
private EventIterator(Iterator<DiffXEvent> iterator) {
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return this.iterator.hasNext();
|
||||
}
|
||||
|
||||
public DiffXEvent next() {
|
||||
return this.iterator.next();
|
||||
}
|
||||
|
||||
public DiffXEvent nextEvent() throws NoSuchElementException {
|
||||
return this.iterator.next();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
this.iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.topologi.diffx.sequence;
|
||||
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import java.util.Stack;
|
||||
|
||||
public final class EventSequenceUtils {
|
||||
public static boolean isWellFormed(EventSequence sequence) {
|
||||
if (sequence == null)
|
||||
return false;
|
||||
Stack<DiffXEvent> open = new Stack<DiffXEvent>();
|
||||
DiffXEvent e = null;
|
||||
for (int i = 0; i < sequence.size(); i++) {
|
||||
e = sequence.getEvent(i);
|
||||
if (e instanceof OpenElementEvent) {
|
||||
open.push(e);
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
if (open.empty())
|
||||
return false;
|
||||
OpenElementEvent o = (OpenElementEvent)open.peek();
|
||||
String lastOpenElementName = o.getName();
|
||||
String closeElementName = ((CloseElementEvent)e).getName();
|
||||
if (!closeElementName.equals(lastOpenElementName))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return open.empty();
|
||||
}
|
||||
|
||||
public static int getMaxDepth(EventSequence sequence) {
|
||||
int max = 0;
|
||||
int depth = 0;
|
||||
for (int i = 0; i < sequence.size(); i++) {
|
||||
if (sequence.getEvent(i) instanceof OpenElementEvent) {
|
||||
depth++;
|
||||
} else if (sequence.getEvent(i) instanceof CloseElementEvent) {
|
||||
depth--;
|
||||
}
|
||||
if (depth > max)
|
||||
max = depth;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
public static int getMaxElementContent(EventSequence sequence) {
|
||||
int max = 0;
|
||||
int tmp = 0;
|
||||
for (int i = 0; i < sequence.size(); i++) {
|
||||
DiffXEvent e = sequence.getEvent(i);
|
||||
if (e instanceof OpenElementEvent) {
|
||||
tmp = 0;
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
if (tmp > max)
|
||||
max = tmp;
|
||||
} else {
|
||||
tmp++;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
package com.topologi.diffx.sequence;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
||||
public final class NaiveSequenceSlicer {
|
||||
final EventSequence sequence1;
|
||||
|
||||
final EventSequence sequence2;
|
||||
|
||||
EventSequence start;
|
||||
|
||||
EventSequence end;
|
||||
|
||||
public NaiveSequenceSlicer(EventSequence seq0, EventSequence seq1) {
|
||||
this.sequence1 = seq0;
|
||||
this.sequence2 = seq1;
|
||||
}
|
||||
|
||||
public int sliceStart() throws IllegalStateException {
|
||||
if (this.start != null)
|
||||
throw new IllegalStateException("The start buffer already contains a subsequence.");
|
||||
this.start = new EventSequence();
|
||||
int count = 0;
|
||||
Iterator<DiffXEvent> i = this.sequence1.eventIterator();
|
||||
Iterator<DiffXEvent> j = this.sequence2.eventIterator();
|
||||
while (i.hasNext() && j.hasNext()) {
|
||||
DiffXEvent e = i.next();
|
||||
if (j.next().equals(e)) {
|
||||
count++;
|
||||
i.remove();
|
||||
j.remove();
|
||||
this.start.addEvent(e);
|
||||
continue;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public int sliceEnd() throws IllegalStateException {
|
||||
if (this.end != null)
|
||||
throw new IllegalStateException("The end buffer already contains a subsequence.");
|
||||
this.end = new EventSequence();
|
||||
int count = 0;
|
||||
int pos1 = this.sequence1.size() - 1;
|
||||
int pos2 = this.sequence2.size() - 1;
|
||||
while (pos1 >= 0 && pos2 >= 0) {
|
||||
DiffXEvent e1 = this.sequence1.getEvent(pos1);
|
||||
if (e1.equals(this.sequence2.getEvent(pos2))) {
|
||||
count++;
|
||||
this.sequence1.removeEvent(pos1--);
|
||||
this.sequence2.removeEvent(pos2--);
|
||||
this.end.addEvent(0, e1);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public int sliceStart(DiffXFormatter formatter) throws IllegalStateException, NullPointerException, IOException {
|
||||
if (this.start != null)
|
||||
throw new IllegalStateException("The start buffer already contains a subsequence.");
|
||||
int count = 0;
|
||||
Iterator<DiffXEvent> i = this.sequence1.eventIterator();
|
||||
Iterator<DiffXEvent> j = this.sequence2.eventIterator();
|
||||
while (i.hasNext() && j.hasNext()) {
|
||||
DiffXEvent e = i.next();
|
||||
if (j.next().equals(e)) {
|
||||
count++;
|
||||
i.remove();
|
||||
j.remove();
|
||||
formatter.format(e);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public int sliceEnd(DiffXFormatter formatter) throws IllegalStateException, NullPointerException, IOException {
|
||||
int count = sliceEnd();
|
||||
formatEnd(formatter);
|
||||
return count;
|
||||
}
|
||||
|
||||
public void formatStart(DiffXFormatter formatter) throws NullPointerException, IOException {
|
||||
if (this.start == null)
|
||||
return;
|
||||
for (int i = 0; i < this.start.size(); i++)
|
||||
formatter.format(this.start.getEvent(i));
|
||||
this.start = null;
|
||||
}
|
||||
|
||||
public void formatEnd(DiffXFormatter formatter) throws NullPointerException, IOException {
|
||||
if (this.end == null)
|
||||
return;
|
||||
for (int i = 0; i < this.end.size(); i++)
|
||||
formatter.format(this.end.getEvent(i));
|
||||
this.end = null;
|
||||
}
|
||||
|
||||
public EventSequence getStart() {
|
||||
return this.start;
|
||||
}
|
||||
|
||||
public EventSequence getEnd() {
|
||||
return this.end;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.topologi.diffx.sequence;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class PrefixMapping {
|
||||
private final Map<String, String> mappings = new HashMap<String, String>();
|
||||
|
||||
public void add(String uri, String prefix) throws NullPointerException {
|
||||
if (!this.mappings.containsKey(uri)) {
|
||||
int count = 0;
|
||||
String actualPrefix = prefix;
|
||||
while (this.mappings.containsValue(actualPrefix))
|
||||
actualPrefix = prefix + count++;
|
||||
this.mappings.put(uri, actualPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
public Enumeration<String> getURIs() {
|
||||
return Collections.<String>enumeration(this.mappings.keySet());
|
||||
}
|
||||
|
||||
public String getPrefix(String uri) {
|
||||
return (uri == null) ? "" : this.mappings.get(uri);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
package com.topologi.diffx.sequence;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
||||
public final class SequenceSlicer {
|
||||
final EventSequence sequence1;
|
||||
|
||||
final EventSequence sequence2;
|
||||
|
||||
EventSequence start;
|
||||
|
||||
EventSequence end;
|
||||
|
||||
public SequenceSlicer(EventSequence seq0, EventSequence seq1) {
|
||||
this.sequence1 = seq0;
|
||||
this.sequence2 = seq1;
|
||||
}
|
||||
|
||||
public void slice() throws IllegalStateException {
|
||||
sliceStart();
|
||||
sliceEnd();
|
||||
}
|
||||
|
||||
public int sliceStart() throws IllegalStateException {
|
||||
if (this.start != null)
|
||||
throw new IllegalStateException("The start buffer already contains a subsequence.");
|
||||
this.start = new EventSequence();
|
||||
int toBeRemoved = 0;
|
||||
int depth = 0;
|
||||
Iterator<DiffXEvent> i = this.sequence1.eventIterator();
|
||||
Iterator<DiffXEvent> j = this.sequence2.eventIterator();
|
||||
int counter = 0;
|
||||
while (i.hasNext() && j.hasNext()) {
|
||||
DiffXEvent e = i.next();
|
||||
if (j.next().equals(e)) {
|
||||
counter++;
|
||||
if (e instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
depth++;
|
||||
} else if (e instanceof com.topologi.diffx.event.CloseElementEvent) {
|
||||
depth--;
|
||||
}
|
||||
if (depth == 1 || depth == 0)
|
||||
toBeRemoved = counter;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (int k = 0; k < toBeRemoved; k++) {
|
||||
DiffXEvent e = this.sequence1.removeEvent(0);
|
||||
this.sequence2.removeEvent(0);
|
||||
this.start.addEvent(e);
|
||||
}
|
||||
return toBeRemoved;
|
||||
}
|
||||
|
||||
public int sliceEnd() throws IllegalStateException {
|
||||
if (this.end != null)
|
||||
throw new IllegalStateException("The end buffer already contains a subsequence.");
|
||||
this.end = new EventSequence();
|
||||
int depth = 0;
|
||||
int toBeRemoved = 0;
|
||||
int counter = 0;
|
||||
int pos1 = this.sequence1.size() - 1;
|
||||
int pos2 = this.sequence2.size() - 1;
|
||||
while (pos1 >= 0 && pos2 >= 0) {
|
||||
DiffXEvent e1 = this.sequence1.getEvent(pos1);
|
||||
if (e1.equals(this.sequence2.getEvent(pos2))) {
|
||||
counter++;
|
||||
if (e1 instanceof com.topologi.diffx.event.CloseElementEvent) {
|
||||
depth++;
|
||||
} else if (e1 instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
depth--;
|
||||
}
|
||||
if (depth == 1 || depth == 0)
|
||||
toBeRemoved = counter;
|
||||
pos1--;
|
||||
pos2--;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
int downTo = this.sequence1.size() - toBeRemoved;
|
||||
for (int i = this.sequence1.size() - 1; i >= downTo; i--) {
|
||||
DiffXEvent e = this.sequence1.removeEvent(i);
|
||||
this.end.addEvent(0, e);
|
||||
}
|
||||
downTo = this.sequence2.size() - toBeRemoved;
|
||||
for (int k = this.sequence2.size() - 1; k >= downTo; k--)
|
||||
this.sequence2.removeEvent(k);
|
||||
return toBeRemoved;
|
||||
}
|
||||
|
||||
public void formatStart(DiffXFormatter formatter) throws NullPointerException, IOException {
|
||||
if (this.start == null)
|
||||
return;
|
||||
for (int i = 0; i < this.start.size(); i++)
|
||||
formatter.format(this.start.getEvent(i));
|
||||
this.start = null;
|
||||
}
|
||||
|
||||
public void formatEnd(DiffXFormatter formatter) throws NullPointerException, IOException {
|
||||
if (this.end == null)
|
||||
return;
|
||||
for (int i = 0; i < this.end.size(); i++)
|
||||
formatter.format(this.end.getEvent(i));
|
||||
this.end = null;
|
||||
}
|
||||
|
||||
public EventSequence getStart() {
|
||||
return this.start;
|
||||
}
|
||||
|
||||
public EventSequence getEnd() {
|
||||
return this.end;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.topologi.diffx.util;
|
||||
|
||||
public final class CommandLine {
|
||||
public static String getParameter(String name, String[] args) {
|
||||
if (args == null || args.length < 2 || name == null)
|
||||
return null;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (name.equals(args[i]) && i + 1 < args.length)
|
||||
return args[i + 1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean hasSwitch(String name, String[] args) {
|
||||
if (args == null || name == null)
|
||||
return false;
|
||||
for (String arg : args) {
|
||||
if (name.equals(arg))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.topologi.diffx.util;
|
||||
|
||||
public final class Constants {
|
||||
public static final String BASE_NS_URI = "http://www.topologi.com/2005/Diff-X";
|
||||
|
||||
public static final String DELETE_NS_URI = "http://www.topologi.com/2005/Diff-X/Delete";
|
||||
|
||||
public static final String INSERT_NS_URI = "http://www.topologi.com/2005/Diff-X/Insert";
|
||||
|
||||
@Deprecated
|
||||
public static final String DEFAULT_URI = "";
|
||||
|
||||
@Deprecated
|
||||
public static final String XML_NS_PREFIX = "xml";
|
||||
|
||||
@Deprecated
|
||||
public static final String XML_NS_URI = "http://www.w3.org/XML/1998/namespace";
|
||||
|
||||
@Deprecated
|
||||
public static final String XMLNS_ATTRIBUTE_NS_URI = "http://www.w3.org/2000/xmlns/";
|
||||
|
||||
@Deprecated
|
||||
public static final String XMLNS_ATTRIBUTE = "xmlns";
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.topologi.diffx.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
|
||||
public final class XMLFilenameFilter implements FileFilter {
|
||||
public static final String DEFAULT_EXTENSION = "xml";
|
||||
|
||||
@Deprecated
|
||||
public final String ext = "xml";
|
||||
|
||||
public final boolean ignoreCase;
|
||||
|
||||
public XMLFilenameFilter() {
|
||||
this.ignoreCase = false;
|
||||
}
|
||||
|
||||
public XMLFilenameFilter(boolean ignoreCase) {
|
||||
this.ignoreCase = ignoreCase;
|
||||
}
|
||||
|
||||
public boolean accept(File pathname) throws NullPointerException {
|
||||
if (pathname == null)
|
||||
throw new NullPointerException("The specified file is null.");
|
||||
String name = pathname.getName();
|
||||
int dot = name.lastIndexOf('.');
|
||||
if (dot == -1)
|
||||
return false;
|
||||
String local = name.substring(dot + 1);
|
||||
return this.ignoreCase ? "xml".equalsIgnoreCase(local) : "xml".equals(local);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
public final class IllegalCloseElementException extends IllegalStateException {
|
||||
static final long serialVersionUID = 7264175736386596167L;
|
||||
|
||||
public IllegalCloseElementException() {
|
||||
super("Attempting to close an element with no more element to close.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
public final class UnclosedElementException extends IllegalStateException {
|
||||
static final long serialVersionUID = -186657976801720211L;
|
||||
|
||||
public UnclosedElementException(String name) {
|
||||
super("Attempting to close the XML Writer while element " + name + " has not been closed.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
public final class UndeclaredNamespaceException extends RuntimeException {
|
||||
static final long serialVersionUID = 8080581405972912943L;
|
||||
|
||||
public UndeclaredNamespaceException(String uri) {
|
||||
super("The namespace URI \"" + uri + "\" has not been mapped to any prefix.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
public interface XMLFormattable {
|
||||
StringBuffer toXML(StringBuffer paramStringBuffer) throws NullPointerException;
|
||||
|
||||
String toXML();
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
public final class XMLHelper {
|
||||
public static XMLReader makeXMLReader(ContentHandler handler) throws SAXException, ParserConfigurationException {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(false);
|
||||
factory.setValidating(false);
|
||||
XMLReader reader = factory.newSAXParser().getXMLReader();
|
||||
if (handler != null)
|
||||
reader.setContentHandler(handler);
|
||||
return reader;
|
||||
}
|
||||
|
||||
public static void parse(XMLReader xmlreader, File file) throws FileNotFoundException, SAXException, IOException {
|
||||
InputStream bin = new BufferedInputStream(new FileInputStream(file));
|
||||
Reader reader = new InputStreamReader(bin, "utf-8");
|
||||
InputSource source = new InputSource(reader);
|
||||
xmlreader.parse(source);
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Stack;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
public final class XMLIndenter extends DefaultHandler implements ContentHandler {
|
||||
private final PrintWriter writer;
|
||||
|
||||
private transient int indentLevel = 0;
|
||||
|
||||
private transient Stack<Integer> states = new Stack<Integer>();
|
||||
|
||||
private static final Integer EMPTY = new Integer(0);
|
||||
|
||||
private static final Integer HAS_TEXT = new Integer(1);
|
||||
|
||||
private static final Integer HAS_CHILDREN = new Integer(2);
|
||||
|
||||
private XMLIndenter(Writer w) {
|
||||
if (w instanceof PrintWriter) {
|
||||
this.writer = (PrintWriter)w;
|
||||
} else {
|
||||
this.writer = new PrintWriter(w);
|
||||
}
|
||||
}
|
||||
|
||||
public void startElement(String uri, String localName, String qName, Attributes atts) {
|
||||
if (!this.states.empty()) {
|
||||
if (this.states.pop().equals(EMPTY))
|
||||
this.writer.println('>');
|
||||
this.states.push(HAS_CHILDREN);
|
||||
}
|
||||
for (int j = 0; j < this.indentLevel; j++)
|
||||
this.writer.print(" ");
|
||||
this.writer.print('<' + qName);
|
||||
for (int i = 0; i < atts.getLength(); i++)
|
||||
this.writer.print(' ' + atts.getQName(i) + "=\"" + atts.getValue(i) + '"');
|
||||
this.indentLevel++;
|
||||
this.states.push(EMPTY);
|
||||
}
|
||||
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
this.indentLevel--;
|
||||
Object state = this.states.pop();
|
||||
if (EMPTY.equals(state)) {
|
||||
this.writer.println("/>");
|
||||
} else if (HAS_TEXT.equals(state)) {
|
||||
this.writer.println("</" + qName + '>');
|
||||
} else if (HAS_CHILDREN.equals(state)) {
|
||||
for (int i = 0; i < this.indentLevel; i++)
|
||||
this.writer.print(" ");
|
||||
this.writer.println("</" + qName + '>');
|
||||
}
|
||||
}
|
||||
|
||||
public void characters(char[] ch, int position, int offset) {
|
||||
if (this.states.peek().equals(EMPTY)) {
|
||||
this.states.pop();
|
||||
this.writer.print('>');
|
||||
this.states.push(HAS_TEXT);
|
||||
}
|
||||
this.writer.print(new String(ch, position, offset));
|
||||
}
|
||||
|
||||
public void ignorableWhitespace(char[] ch, int position, int offset) {}
|
||||
|
||||
public static String indent(String xml) throws SAXException, IOException, ParserConfigurationException {
|
||||
Writer writer = new StringWriter();
|
||||
Reader reader = new StringReader(xml);
|
||||
indent(reader, writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
public static void indent(Reader r, Writer w) throws SAXException, IOException, ParserConfigurationException {
|
||||
XMLIndenter indenter = new XMLIndenter(w);
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(false);
|
||||
factory.setValidating(false);
|
||||
InputSource source = new InputSource(r);
|
||||
XMLReader xmlreader = factory.newSAXParser().getXMLReader();
|
||||
xmlreader.setContentHandler(indenter);
|
||||
xmlreader.parse(source);
|
||||
}
|
||||
|
||||
public static String indentSilent(String xml) {
|
||||
try {
|
||||
return indent(xml);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean indentSilent(Reader r, Writer w) {
|
||||
try {
|
||||
indent(r, w);
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
public interface XMLSerializable {}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public final class XMLSerializer {
|
||||
private static final DateFormat DF = new SimpleDateFormat("dd/MM/yyyy");
|
||||
|
||||
private final XMLWriter xml;
|
||||
|
||||
public XMLSerializer(XMLWriter xml) {
|
||||
this.xml = xml;
|
||||
}
|
||||
|
||||
public XMLWriter getXML() {
|
||||
return this.xml;
|
||||
}
|
||||
|
||||
public void serialize(Object o, String name) throws IOException {
|
||||
if (o != null) {
|
||||
if (name.lastIndexOf('.') != -1)
|
||||
name = name.substring(name.lastIndexOf('.') + 1);
|
||||
if (name.lastIndexOf('$') != -1)
|
||||
name = name.substring(name.lastIndexOf('$') + 1);
|
||||
name = name.toLowerCase();
|
||||
if (o instanceof Number) {
|
||||
this.xml.openElement(name, false);
|
||||
this.xml.writeText(o.toString());
|
||||
this.xml.closeElement();
|
||||
} else if (o instanceof String) {
|
||||
this.xml.openElement(name, false);
|
||||
this.xml.writeText(o.toString());
|
||||
this.xml.closeElement();
|
||||
} else if (o instanceof Character) {
|
||||
this.xml.openElement(name, false);
|
||||
this.xml.writeText(((Character)o).charValue());
|
||||
this.xml.closeElement();
|
||||
} else if (o instanceof Boolean) {
|
||||
this.xml.openElement(name, false);
|
||||
this.xml.writeText(o.toString());
|
||||
this.xml.closeElement();
|
||||
} else if (o instanceof Date) {
|
||||
this.xml.openElement(name, false);
|
||||
this.xml.writeText(DF.format((Date)o));
|
||||
this.xml.closeElement();
|
||||
} else if (o instanceof Collection) {
|
||||
this.xml.openElement(name, (((Collection)o).size() != 0));
|
||||
serializeCollection((Collection)o);
|
||||
this.xml.closeElement();
|
||||
} else if (o instanceof Hashtable) {
|
||||
this.xml.openElement(name, (((Hashtable)o).size() != 0));
|
||||
serializeHashtable((Hashtable<?, ?>)o);
|
||||
this.xml.closeElement();
|
||||
} else {
|
||||
this.xml.openElement(name, true);
|
||||
serializeObject(o);
|
||||
this.xml.closeElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void serializeCollection(Collection<?> c) throws IOException {
|
||||
for (Object o : (Iterable<Object>)c)
|
||||
serialize(o, o.getClass().getName());
|
||||
}
|
||||
|
||||
public void serializeHashtable(Hashtable<?, ?> h) throws IOException {
|
||||
this.xml.openElement("map", !h.isEmpty());
|
||||
for (Enumeration<?> e = h.keys(); e.hasMoreElements(); ) {
|
||||
Object key = e.nextElement();
|
||||
Object value = h.get(key);
|
||||
this.xml.openElement("element");
|
||||
this.xml.openElement("key");
|
||||
serialize(key, "key");
|
||||
this.xml.closeElement();
|
||||
this.xml.openElement("value");
|
||||
serialize(value, "value");
|
||||
this.xml.closeElement();
|
||||
this.xml.closeElement();
|
||||
}
|
||||
this.xml.closeElement();
|
||||
}
|
||||
|
||||
public void serializeObject(Object o) throws IOException {
|
||||
if (o instanceof XMLSerializable) {
|
||||
try {
|
||||
Object[] args = new Object[0];
|
||||
Class<?> cls = o.getClass();
|
||||
Method[] meth = cls.getMethods();
|
||||
for (Method element : meth) {
|
||||
String methodName = element.getName();
|
||||
if (methodName.startsWith("get") && !"getClass".equals(methodName)) {
|
||||
Object retObj = element.invoke(o, args);
|
||||
String attribute = methodName.substring(3).toLowerCase();
|
||||
serialize(retObj, attribute);
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException ex) {
|
||||
ex.printStackTrace();
|
||||
} catch (InvocationTargetException ex) {
|
||||
ex.getTargetException().printStackTrace();
|
||||
}
|
||||
} else if (o instanceof XMLWritable) {
|
||||
((XMLWritable)o).toXML(this.xml);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
|
||||
public final class XMLStringWriter implements XMLWriter {
|
||||
private final StringWriter writer;
|
||||
|
||||
private final XMLWriter xml;
|
||||
|
||||
public XMLStringWriter(boolean namespaces) {
|
||||
this(namespaces, false);
|
||||
}
|
||||
|
||||
public XMLStringWriter(boolean namespaces, boolean indent) {
|
||||
this.writer = new StringWriter();
|
||||
this.xml = namespaces ? new XMLWriterNSImpl(this.writer, indent) : new XMLWriterImpl(this.writer, indent);
|
||||
}
|
||||
|
||||
public void xmlDecl() {
|
||||
try {
|
||||
this.xml.xmlDecl();
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void setIndentChars(String spaces) {
|
||||
this.xml.setIndentChars(spaces);
|
||||
}
|
||||
|
||||
public void writeText(char c) {
|
||||
try {
|
||||
this.xml.writeText(c);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeText(String text) {
|
||||
try {
|
||||
this.xml.writeText(text);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeText(char[] text, int off, int len) {
|
||||
try {
|
||||
this.xml.writeText(text, off, len);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeCDATA(String cdata) {
|
||||
try {
|
||||
this.xml.writeCDATA(cdata);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeXML(String text) {
|
||||
try {
|
||||
this.xml.writeXML(text);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeXML(char[] text, int off, int len) {
|
||||
try {
|
||||
this.xml.writeXML(text, off, len);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeComment(String comment) {
|
||||
try {
|
||||
this.xml.writeComment(comment);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writePI(String target, String data) {
|
||||
try {
|
||||
this.xml.writePI(target, data);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void openElement(String name) {
|
||||
try {
|
||||
this.xml.openElement(name);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void openElement(String name, boolean hasChildren) {
|
||||
try {
|
||||
this.xml.openElement(name, hasChildren);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name, boolean hasChildren) {
|
||||
try {
|
||||
this.xml.openElement(uri, name, hasChildren);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void closeElement() {
|
||||
try {
|
||||
this.xml.closeElement();
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void element(String name, String text) {
|
||||
try {
|
||||
this.xml.element(name, text);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void emptyElement(String element) {
|
||||
try {
|
||||
this.xml.emptyElement(element);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void emptyElement(String uri, String element) {
|
||||
try {
|
||||
this.xml.emptyElement(element);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void attribute(String name, String value) {
|
||||
try {
|
||||
this.xml.attribute(name, value);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void attribute(String name, int value) {
|
||||
try {
|
||||
this.xml.attribute(name, value);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, String value) {
|
||||
try {
|
||||
this.xml.attribute(uri, name, value);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, int value) {
|
||||
try {
|
||||
this.xml.attribute(uri, name, value);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void setPrefixMapping(String uri, String prefix) {
|
||||
this.xml.setPrefixMapping(uri, prefix);
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
try {
|
||||
this.xml.flush();
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws UnclosedElementException {
|
||||
try {
|
||||
this.xml.close();
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.writer.toString();
|
||||
}
|
||||
|
||||
private static void doNothing() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import com.topologi.diffx.xml.esc.XMLEscapeUTF8;
|
||||
|
||||
public final class XMLUtils {
|
||||
public static String escape(String s) {
|
||||
return XMLEscapeUTF8.UTF8_ESCAPE.toElementText(s);
|
||||
}
|
||||
|
||||
public static String escapeAttr(String s) {
|
||||
return XMLEscapeUTF8.UTF8_ESCAPE.toAttributeValue(s);
|
||||
}
|
||||
|
||||
public static String toElementName(String name) {
|
||||
if (name == null)
|
||||
return null;
|
||||
char[] elementAsChars = name.toCharArray();
|
||||
if (!Character.isLetter(elementAsChars[0])) {
|
||||
elementAsChars[0] = 'x';
|
||||
} else {
|
||||
elementAsChars[0] = Character.toLowerCase(elementAsChars[0]);
|
||||
}
|
||||
for (int i = 1; i < elementAsChars.length; i++) {
|
||||
if (!Character.isLetter(elementAsChars[i])) {
|
||||
elementAsChars[i] = '-';
|
||||
} else {
|
||||
elementAsChars[i] = Character.toLowerCase(elementAsChars[i]);
|
||||
}
|
||||
}
|
||||
return new String(elementAsChars);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface XMLWritable {
|
||||
void toXML(XMLWriter paramXMLWriter) throws IOException;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface XMLWriter {
|
||||
void xmlDecl() throws IOException;
|
||||
|
||||
void setIndentChars(String paramString);
|
||||
|
||||
void writeText(char paramChar) throws IOException;
|
||||
|
||||
void writeText(String paramString) throws IOException;
|
||||
|
||||
void writeText(char[] paramArrayOfchar, int paramInt1, int paramInt2) throws IOException;
|
||||
|
||||
void writeCDATA(String paramString) throws IOException;
|
||||
|
||||
void writeXML(String paramString) throws IOException;
|
||||
|
||||
void writeXML(char[] paramArrayOfchar, int paramInt1, int paramInt2) throws IOException;
|
||||
|
||||
void writeComment(String paramString) throws IOException;
|
||||
|
||||
void writePI(String paramString1, String paramString2) throws IOException;
|
||||
|
||||
void openElement(String paramString) throws IOException;
|
||||
|
||||
void openElement(String paramString, boolean paramBoolean) throws IOException;
|
||||
|
||||
void openElement(String paramString1, String paramString2, boolean paramBoolean) throws IOException;
|
||||
|
||||
void closeElement() throws IOException;
|
||||
|
||||
void element(String paramString1, String paramString2) throws IOException;
|
||||
|
||||
void emptyElement(String paramString) throws IOException;
|
||||
|
||||
void emptyElement(String paramString1, String paramString2) throws IOException;
|
||||
|
||||
void attribute(String paramString1, String paramString2) throws IOException;
|
||||
|
||||
void attribute(String paramString, int paramInt) throws IOException;
|
||||
|
||||
void attribute(String paramString1, String paramString2, String paramString3) throws IOException;
|
||||
|
||||
void attribute(String paramString1, String paramString2, int paramInt) throws IOException;
|
||||
|
||||
void setPrefixMapping(String paramString1, String paramString2);
|
||||
|
||||
void flush() throws IOException;
|
||||
|
||||
void close() throws IOException;
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import com.topologi.diffx.xml.esc.XMLEscapeWriter;
|
||||
import com.topologi.diffx.xml.esc.XMLEscapeWriterUTF8;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
abstract class XMLWriterBase implements XMLWriter {
|
||||
final Writer writer;
|
||||
|
||||
String encoding = "utf-8";
|
||||
|
||||
XMLEscapeWriter writerEscape;
|
||||
|
||||
int depth = 0;
|
||||
|
||||
boolean indent;
|
||||
|
||||
private String indentChars = null;
|
||||
|
||||
boolean isNude = false;
|
||||
|
||||
public XMLWriterBase(Writer writer, boolean indent) throws NullPointerException {
|
||||
if (writer == null)
|
||||
throw new NullPointerException("XMLWriter cannot use a null writer.");
|
||||
this.writer = writer;
|
||||
this.writerEscape = new XMLEscapeWriterUTF8(writer);
|
||||
this.indent = indent;
|
||||
if (indent)
|
||||
this.indentChars = " ";
|
||||
}
|
||||
|
||||
public final void xmlDecl() throws IOException {
|
||||
this.writer.write("<?xml version=\"1.0\" encoding=\"" + this.encoding + "\"?>");
|
||||
if (this.indent)
|
||||
this.writer.write(10);
|
||||
}
|
||||
|
||||
public final void setIndentChars(String spaces) throws IllegalStateException, IllegalArgumentException {
|
||||
if (this.depth != 0)
|
||||
throw new IllegalStateException("To late to set the indentation characters!");
|
||||
if (spaces != null)
|
||||
for (int i = 0; i < spaces.length(); i++) {
|
||||
if (!Character.isSpaceChar(spaces.charAt(i)))
|
||||
throw new IllegalArgumentException("Not a valid indentation string.");
|
||||
}
|
||||
this.indentChars = spaces;
|
||||
this.indent = (spaces != null);
|
||||
}
|
||||
|
||||
public final void setEncoding(String encoding) throws IllegalStateException, IllegalArgumentException {
|
||||
if (this.depth != 0)
|
||||
throw new IllegalStateException("To late to set the encoding!");
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
public final void writeText(String text) throws IOException {
|
||||
if (text == null)
|
||||
return;
|
||||
deNude();
|
||||
this.writerEscape.writeText(text);
|
||||
}
|
||||
|
||||
public final void writeText(char[] text, int off, int len) throws IOException {
|
||||
deNude();
|
||||
this.writerEscape.writeText(text, off, len);
|
||||
}
|
||||
|
||||
public final void writeText(char c) throws IOException {
|
||||
deNude();
|
||||
this.writerEscape.writeText(c);
|
||||
}
|
||||
|
||||
public final void writeText(Object o) throws IOException {
|
||||
if (o != null)
|
||||
writeText(o.toString());
|
||||
}
|
||||
|
||||
public final void writeXML(String text) throws IOException {
|
||||
if (text == null)
|
||||
return;
|
||||
deNude();
|
||||
this.writer.write(text);
|
||||
}
|
||||
|
||||
public final void writeXML(char[] text, int off, int len) throws IOException {
|
||||
deNude();
|
||||
this.writer.write(text, off, len);
|
||||
}
|
||||
|
||||
public final void writeComment(String comment) throws IOException, IllegalArgumentException {
|
||||
if (comment == null)
|
||||
return;
|
||||
if (comment.indexOf("--") >= 0)
|
||||
throw new IllegalArgumentException("A comment must not contain '--'.");
|
||||
deNude();
|
||||
this.writer.write("<!-- ");
|
||||
this.writer.write(comment);
|
||||
this.writer.write(" -->");
|
||||
if (this.indent)
|
||||
this.writer.write(10);
|
||||
}
|
||||
|
||||
public final void writePI(String target, String data) throws IOException {
|
||||
deNude();
|
||||
this.writer.write("<?");
|
||||
this.writer.write(target);
|
||||
this.writer.write(32);
|
||||
this.writer.write(data);
|
||||
this.writer.write("?>");
|
||||
if (this.indent)
|
||||
this.writer.write(10);
|
||||
}
|
||||
|
||||
public final void writeCDATA(String data) throws IOException {
|
||||
if (data == null)
|
||||
return;
|
||||
String end = "]]>";
|
||||
if (data.indexOf("]]>") >= 0)
|
||||
throw new IllegalArgumentException("CDATA sections must not contain ']]>'");
|
||||
deNude();
|
||||
this.writer.write("<![CDATA[");
|
||||
this.writer.write(data);
|
||||
this.writer.write("]]>");
|
||||
}
|
||||
|
||||
public final void attribute(String name, String value) throws IOException {
|
||||
if (!this.isNude)
|
||||
throw new IllegalStateException("Cannot write attribute: too late!");
|
||||
this.writer.write(32);
|
||||
this.writer.write(name);
|
||||
this.writer.write(61);
|
||||
this.writer.write(34);
|
||||
this.writerEscape.writeAttValue(value);
|
||||
this.writer.write(34);
|
||||
}
|
||||
|
||||
public final void attribute(String name, int value) throws IOException {
|
||||
if (!this.isNude)
|
||||
throw new IllegalStateException("Cannot write attribute: too late!");
|
||||
this.writer.write(32);
|
||||
this.writer.write(name);
|
||||
this.writer.write(61);
|
||||
this.writer.write(34);
|
||||
this.writer.write(Integer.toString(value));
|
||||
this.writer.write(34);
|
||||
}
|
||||
|
||||
public void element(String name, String text) throws IOException {
|
||||
openElement(name);
|
||||
writeText(text);
|
||||
closeElement();
|
||||
}
|
||||
|
||||
public final void flush() throws IOException {
|
||||
this.writer.flush();
|
||||
}
|
||||
|
||||
abstract void deNude() throws IOException;
|
||||
|
||||
void indent() throws IOException {
|
||||
if (this.indent)
|
||||
for (int i = 0; i < this.depth; i++)
|
||||
this.writer.write(this.indentChars);
|
||||
}
|
||||
|
||||
static final void doNothing() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class XMLWriterImpl extends XMLWriterBase implements XMLWriter {
|
||||
private static final Element ROOT = new Element("", true);
|
||||
|
||||
private final List<Element> elements = new ArrayList<Element>();
|
||||
|
||||
public XMLWriterImpl(Writer writer) throws NullPointerException {
|
||||
super(writer, false);
|
||||
this.elements.add(ROOT);
|
||||
}
|
||||
|
||||
public XMLWriterImpl(Writer writer, boolean indent) throws NullPointerException {
|
||||
super(writer, indent);
|
||||
this.elements.add(ROOT);
|
||||
}
|
||||
|
||||
void deNude() throws IOException {
|
||||
if (this.isNude) {
|
||||
this.writer.write(62);
|
||||
if ((peekElement()).hasChildren && this.indent)
|
||||
this.writer.write(10);
|
||||
this.isNude = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void openElement(String name) throws IOException {
|
||||
openElement(name, false);
|
||||
}
|
||||
|
||||
public void openElement(String name, boolean hasChildren) throws IOException {
|
||||
deNude();
|
||||
indent();
|
||||
this.elements.add(new Element(name, hasChildren));
|
||||
this.writer.write(60);
|
||||
this.writer.write(name);
|
||||
this.isNude = true;
|
||||
this.depth++;
|
||||
}
|
||||
|
||||
public void closeElement() throws IOException, IllegalCloseElementException {
|
||||
Element elt = popElement();
|
||||
if (elt == ROOT)
|
||||
throw new IllegalCloseElementException();
|
||||
this.depth--;
|
||||
if (this.isNude) {
|
||||
this.writer.write(47);
|
||||
this.isNude = false;
|
||||
} else {
|
||||
if (elt.hasChildren)
|
||||
indent();
|
||||
this.writer.write(60);
|
||||
this.writer.write(47);
|
||||
int x = elt.name.indexOf(' ');
|
||||
if (x < 0) {
|
||||
this.writer.write(elt.name);
|
||||
} else {
|
||||
this.writer.write(elt.name.substring(0, x));
|
||||
}
|
||||
}
|
||||
this.writer.write(62);
|
||||
if (this.indent) {
|
||||
Element parent = peekElement();
|
||||
if (parent.hasChildren && parent != ROOT)
|
||||
this.writer.write(10);
|
||||
}
|
||||
}
|
||||
|
||||
public void emptyElement(String element) throws IOException {
|
||||
deNude();
|
||||
indent();
|
||||
this.writer.write(60);
|
||||
this.writer.write(element);
|
||||
this.writer.write(47);
|
||||
this.writer.write(62);
|
||||
if (this.indent) {
|
||||
Element parent = peekElement();
|
||||
if (parent.hasChildren && parent != ROOT)
|
||||
this.writer.write(10);
|
||||
}
|
||||
}
|
||||
|
||||
private Element peekElement() {
|
||||
return this.elements.get(this.elements.size() - 1);
|
||||
}
|
||||
|
||||
private Element popElement() {
|
||||
return (Element)this.elements.remove(this.elements.size() - 1);
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces.");
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name, boolean hasChildren) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces.");
|
||||
}
|
||||
|
||||
public void emptyElement(String uri, String element) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void setPrefixMapping(String uri, String prefix) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, String value) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, int value) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void close() throws IOException, UnclosedElementException {
|
||||
Element open = peekElement();
|
||||
if (open != ROOT)
|
||||
throw new UnclosedElementException(open.name);
|
||||
this.writer.close();
|
||||
}
|
||||
|
||||
private static final class Element {
|
||||
private final String name;
|
||||
|
||||
private final boolean hasChildren;
|
||||
|
||||
public Element(String name, boolean hasChildren) {
|
||||
this.name = name;
|
||||
this.hasChildren = hasChildren;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class XMLWriterNSImpl extends XMLWriterBase implements XMLWriter {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final PrefixMapping DEFAULT_NS = new PrefixMapping("", "");
|
||||
|
||||
private static final Element ROOT;
|
||||
|
||||
static {
|
||||
List<PrefixMapping> mps = new ArrayList<PrefixMapping>();
|
||||
mps.add(DEFAULT_NS);
|
||||
ROOT = new Element("", true, mps);
|
||||
}
|
||||
|
||||
private final Map<String, String> prefixMapping = new HashMap<String, String>();
|
||||
|
||||
private List<PrefixMapping> tempMapping;
|
||||
|
||||
private final List<Element> elements = new ArrayList<Element>();
|
||||
|
||||
public XMLWriterNSImpl(Writer writer) throws NullPointerException {
|
||||
this(writer, false);
|
||||
}
|
||||
|
||||
public XMLWriterNSImpl(Writer writer, boolean indent) throws NullPointerException {
|
||||
super(writer, indent);
|
||||
this.elements.add(ROOT);
|
||||
this.prefixMapping.put("", "");
|
||||
this.prefixMapping.put("http://www.w3.org/XML/1998/namespace", "xml");
|
||||
}
|
||||
|
||||
void deNude() throws IOException {
|
||||
if (this.isNude) {
|
||||
this.writer.write(62);
|
||||
if (this.indent && (peekElement()).hasChildren)
|
||||
this.writer.write(10);
|
||||
this.isNude = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void openElement(String name) throws IOException {
|
||||
openElement(null, name, false);
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name) throws IOException {
|
||||
openElement(uri, name, false);
|
||||
}
|
||||
|
||||
public void openElement(String name, boolean hasChildren) throws IOException {
|
||||
openElement(null, name, hasChildren);
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name, boolean hasChildren) throws IOException {
|
||||
deNude();
|
||||
indent();
|
||||
String qName = getQName(uri, name);
|
||||
this.elements.add(new Element(qName, hasChildren, this.tempMapping));
|
||||
this.writer.write(60);
|
||||
this.writer.write(qName);
|
||||
handleNamespaceDeclaration();
|
||||
this.isNude = true;
|
||||
this.depth++;
|
||||
}
|
||||
|
||||
public void closeElement() throws IOException {
|
||||
Element elt = popElement();
|
||||
if (elt == ROOT)
|
||||
throw new IllegalCloseElementException();
|
||||
this.depth--;
|
||||
if (this.isNude) {
|
||||
this.writer.write(47);
|
||||
this.isNude = false;
|
||||
} else {
|
||||
if (elt.hasChildren)
|
||||
indent();
|
||||
this.writer.write(60);
|
||||
this.writer.write(47);
|
||||
int x = elt.qName.indexOf(' ');
|
||||
if (x < 0) {
|
||||
this.writer.write(elt.qName);
|
||||
} else {
|
||||
this.writer.write(elt.qName.substring(0, x));
|
||||
}
|
||||
}
|
||||
restorePrefixMapping(elt);
|
||||
this.writer.write(62);
|
||||
if (this.indent) {
|
||||
Element parent = peekElement();
|
||||
if (parent.hasChildren && parent != ROOT)
|
||||
this.writer.write(10);
|
||||
}
|
||||
}
|
||||
|
||||
public void emptyElement(String element) throws IOException {
|
||||
emptyElement(null, element);
|
||||
}
|
||||
|
||||
public void emptyElement(String uri, String element) throws IOException {
|
||||
deNude();
|
||||
indent();
|
||||
this.writer.write(60);
|
||||
this.writer.write(getQName(uri, element));
|
||||
handleNamespaceDeclaration();
|
||||
this.writer.write(47);
|
||||
this.writer.write(62);
|
||||
if (this.indent)
|
||||
this.writer.write(10);
|
||||
}
|
||||
|
||||
private Element peekElement() {
|
||||
return this.elements.get(this.elements.size() - 1);
|
||||
}
|
||||
|
||||
private Element popElement() {
|
||||
return (Element)this.elements.remove(this.elements.size() - 1);
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, String value) throws IOException, IllegalStateException {
|
||||
if (!this.isNude)
|
||||
throw new IllegalArgumentException("Cannot write attribute: too late!");
|
||||
this.writer.write(32);
|
||||
this.writer.write(getQName(uri, name));
|
||||
this.writer.write("=\"");
|
||||
this.writerEscape.writeAttValue(value);
|
||||
this.writer.write(34);
|
||||
handleNamespaceDeclaration();
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, int value) throws IOException, IllegalStateException {
|
||||
if (!this.isNude)
|
||||
throw new IllegalArgumentException("Cannot write attribute: too late!");
|
||||
this.writer.write(32);
|
||||
this.writer.write(getQName(uri, name));
|
||||
this.writer.write("=\"");
|
||||
this.writer.write(Integer.toString(value));
|
||||
this.writer.write(34);
|
||||
handleNamespaceDeclaration();
|
||||
}
|
||||
|
||||
public void setPrefixMapping(String uri, String prefix) throws NullPointerException {
|
||||
if (!prefix.equals(this.prefixMapping.get(uri))) {
|
||||
removeIfNeeded(prefix);
|
||||
PrefixMapping pm = new PrefixMapping(prefix, uri);
|
||||
this.prefixMapping.put(pm.uri, pm.prefix);
|
||||
if (this.tempMapping == null)
|
||||
this.tempMapping = new ArrayList<PrefixMapping>();
|
||||
this.tempMapping.add(pm);
|
||||
}
|
||||
}
|
||||
|
||||
private String getQName(String uri, String name) throws UndeclaredNamespaceException {
|
||||
String prefix = this.prefixMapping.get((uri != null) ? uri : "");
|
||||
if (prefix != null) {
|
||||
if (!"".equals(prefix))
|
||||
return (String)this.prefixMapping.get(uri) + ":" + name;
|
||||
return name;
|
||||
}
|
||||
if (uri == null)
|
||||
return name;
|
||||
throw new UndeclaredNamespaceException(uri);
|
||||
}
|
||||
|
||||
private void handleNamespaceDeclaration() throws IOException {
|
||||
if (this.tempMapping != null) {
|
||||
PrefixMapping pm = null;
|
||||
for (int i = 0; i < this.tempMapping.size(); i++) {
|
||||
pm = this.tempMapping.get(i);
|
||||
if (!"xml".equals(pm.prefix)) {
|
||||
this.writer.write(" xmlns");
|
||||
if (!"".equals(pm.prefix)) {
|
||||
this.writer.write(58);
|
||||
this.writer.write(pm.prefix);
|
||||
}
|
||||
this.writer.write("=\"");
|
||||
this.writer.write(pm.uri);
|
||||
this.writer.write("\"");
|
||||
}
|
||||
}
|
||||
this.tempMapping = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void restorePrefixMapping(Element elt) {
|
||||
if (elt.mappings != null)
|
||||
for (int i = 0; i < elt.mappings.size(); i++) {
|
||||
PrefixMapping mpi = elt.mappings.get(i);
|
||||
for (int j = this.elements.size() - 1; j > 0; j--) {
|
||||
if ((this.elements.get(j)).mappings != null) {
|
||||
List<PrefixMapping> mps = (this.elements.get(j)).mappings;
|
||||
for (int k = 0; k < mps.size(); k++) {
|
||||
PrefixMapping mpk = mps.get(k);
|
||||
if (mpk.prefix.equals(mpi.prefix)) {
|
||||
removeIfNeeded(mpk.prefix);
|
||||
this.prefixMapping.put(mpk.uri, mpk.prefix);
|
||||
j = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeIfNeeded(String prefix) {
|
||||
if (this.prefixMapping.containsValue(prefix)) {
|
||||
Map.Entry<String, String> remove = null;
|
||||
for (Map.Entry<String, String> e : this.prefixMapping.entrySet()) {
|
||||
if (e.getValue().equals(prefix)) {
|
||||
remove = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.prefixMapping.remove(remove.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException, UnclosedElementException {
|
||||
Element open = peekElement();
|
||||
if (open != ROOT)
|
||||
throw new UnclosedElementException(open.qName);
|
||||
this.writer.close();
|
||||
}
|
||||
|
||||
private static final class Element {
|
||||
private final String qName;
|
||||
|
||||
private final boolean hasChildren;
|
||||
|
||||
private final List<XMLWriterNSImpl.PrefixMapping> mappings;
|
||||
|
||||
public Element(String qName, boolean hasChildren, List<XMLWriterNSImpl.PrefixMapping> mappings) {
|
||||
this.qName = qName;
|
||||
this.hasChildren = hasChildren;
|
||||
this.mappings = mappings;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class PrefixMapping {
|
||||
private final String prefix;
|
||||
|
||||
private final String uri;
|
||||
|
||||
public PrefixMapping(String prefix, String uri) {
|
||||
this.prefix = (prefix != null) ? prefix : "";
|
||||
this.uri = (uri != null) ? uri : "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.topologi.diffx.xml.dom;
|
||||
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
public interface DOMWriter extends XMLWriter {
|
||||
Document getDocument();
|
||||
}
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
package com.topologi.diffx.xml.dom;
|
||||
|
||||
import com.topologi.diffx.xml.IllegalCloseElementException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.DOMException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
public final class DOMWriterImpl implements DOMWriter {
|
||||
private final Document document;
|
||||
|
||||
private final Node newline;
|
||||
|
||||
private boolean indent;
|
||||
|
||||
private String indentChars;
|
||||
|
||||
private transient int depth;
|
||||
|
||||
private transient boolean isNude;
|
||||
|
||||
private transient Node currentElement;
|
||||
|
||||
private transient List<Boolean> childrenFlags = new ArrayList<Boolean>();
|
||||
|
||||
public DOMWriterImpl() throws ParserConfigurationException {
|
||||
this(newDocument());
|
||||
}
|
||||
|
||||
public DOMWriterImpl(Document document) {
|
||||
if (document == null)
|
||||
throw new NullPointerException("The XMLWriter requires a DOM Document to write on.");
|
||||
this.document = document;
|
||||
this.currentElement = document;
|
||||
this.newline = document.createTextNode("\n");
|
||||
}
|
||||
|
||||
public void xmlDecl() {}
|
||||
|
||||
public void setIndentChars(String spaces) {
|
||||
if (this.depth != 0)
|
||||
throw new IllegalStateException("To late to set the indentation characters!");
|
||||
if (spaces != null)
|
||||
for (int i = 0; i < spaces.length(); i++) {
|
||||
if (!Character.isSpaceChar(spaces.charAt(i)))
|
||||
throw new IllegalArgumentException("Not a valid indentation string.");
|
||||
}
|
||||
this.indentChars = spaces;
|
||||
this.indent = (spaces != null);
|
||||
}
|
||||
|
||||
public void writeText(String text) {
|
||||
if (text == null)
|
||||
return;
|
||||
deNude();
|
||||
Text textNode = this.document.createTextNode(text);
|
||||
this.currentElement.appendChild(textNode);
|
||||
}
|
||||
|
||||
public void writeText(char[] text, int off, int len) {
|
||||
writeText(new String(text, off, len));
|
||||
}
|
||||
|
||||
public void writeText(char c) {
|
||||
writeText(new String(new char[] { c }));
|
||||
}
|
||||
|
||||
public void writeText(Object o) {
|
||||
if (o != null)
|
||||
writeText(o.toString());
|
||||
}
|
||||
|
||||
public void writeCDATA(String data) {
|
||||
if (data == null)
|
||||
return;
|
||||
this.document.createCDATASection(data);
|
||||
}
|
||||
|
||||
public void writeXML(String text) {
|
||||
throw new UnsupportedOperationException("Cannot use unparsed XML as DOM node.");
|
||||
}
|
||||
|
||||
public void writeXML(char[] text, int off, int len) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("Cannot use unparsed XML as DOM node.");
|
||||
}
|
||||
|
||||
public void writeComment(String comment) throws DOMException {
|
||||
if (comment.indexOf("--") >= 0)
|
||||
throw new IllegalArgumentException("A comment must not contain '--'.");
|
||||
deNude();
|
||||
Node node = this.document.createComment(comment);
|
||||
this.currentElement.appendChild(node);
|
||||
if (this.indent)
|
||||
newLine();
|
||||
}
|
||||
|
||||
public void writePI(String target, String data) throws DOMException {
|
||||
deNude();
|
||||
Node node = this.document.createProcessingInstruction(target, data);
|
||||
this.currentElement.appendChild(node);
|
||||
if (this.indent)
|
||||
newLine();
|
||||
}
|
||||
|
||||
public void attribute(String name, String value) throws DOMException {
|
||||
if (!this.isNude)
|
||||
throw new IllegalArgumentException("Cannot write attribute: too late!");
|
||||
Attr att = this.document.createAttribute(name);
|
||||
att.setValue(value);
|
||||
this.currentElement.appendChild(att);
|
||||
}
|
||||
|
||||
public void attribute(String name, int value) throws DOMException {
|
||||
attribute(name, Integer.toString(value));
|
||||
}
|
||||
|
||||
public void openElement(String name) throws DOMException {
|
||||
openElement(name, false);
|
||||
}
|
||||
|
||||
public void openElement(String name, boolean hasChildren) throws DOMException {
|
||||
deNude();
|
||||
indent();
|
||||
this.childrenFlags.add(Boolean.valueOf(hasChildren));
|
||||
Element element = this.document.createElement(name);
|
||||
this.currentElement.appendChild(element);
|
||||
this.currentElement = element;
|
||||
this.isNude = true;
|
||||
this.depth++;
|
||||
}
|
||||
|
||||
public void element(String name, String text) throws DOMException {
|
||||
openElement(name);
|
||||
writeText(text);
|
||||
closeElement();
|
||||
}
|
||||
|
||||
public void closeElement() throws DOMException, IllegalCloseElementException {
|
||||
if (this.currentElement.getNodeType() == 9)
|
||||
throw new IllegalCloseElementException();
|
||||
this.depth--;
|
||||
this.isNude = false;
|
||||
Boolean hasChildren = (Boolean)this.childrenFlags.remove(this.childrenFlags.size() - 1);
|
||||
if (hasChildren)
|
||||
indent();
|
||||
this.currentElement.normalize();
|
||||
this.currentElement = this.currentElement.getParentNode();
|
||||
if (this.indent) {
|
||||
Boolean b = this.childrenFlags.get(this.childrenFlags.size() - 1);
|
||||
if (b)
|
||||
newLine();
|
||||
}
|
||||
}
|
||||
|
||||
public void emptyElement(String name) throws DOMException {
|
||||
Element element = this.document.createElement(name);
|
||||
this.currentElement.appendChild(element);
|
||||
}
|
||||
|
||||
public void close() {}
|
||||
|
||||
public void flush() {
|
||||
this.currentElement.normalize();
|
||||
}
|
||||
|
||||
public Document getDocument() {
|
||||
return this.document;
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces.");
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name, boolean hasChildren) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces.");
|
||||
}
|
||||
|
||||
public void emptyElement(String uri, String element) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void setPrefixMapping(String uri, String prefix) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, String value) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, int value) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
void indent() {
|
||||
if (this.indent) {
|
||||
StringBuffer out = new StringBuffer(this.depth * this.indentChars.length());
|
||||
for (int i = 0; i < this.depth; i++)
|
||||
out.append(this.indentChars);
|
||||
Node node = this.document.createTextNode(out.toString());
|
||||
this.currentElement.appendChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
private void deNude() {
|
||||
if (this.isNude) {
|
||||
if (this.indent)
|
||||
newLine();
|
||||
this.isNude = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void newLine() {
|
||||
this.currentElement.appendChild(this.newline.cloneNode(false));
|
||||
}
|
||||
|
||||
private static Document newDocument() throws ParserConfigurationException {
|
||||
DocumentBuilder builder = XmlUtils.getNewDocumentBuilder();
|
||||
return builder.newDocument();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
public interface XMLEscape {
|
||||
String toAttributeValue(char[] paramArrayOfchar, int paramInt1, int paramInt2);
|
||||
|
||||
String toAttributeValue(String paramString);
|
||||
|
||||
String toElementText(char[] paramArrayOfchar, int paramInt1, int paramInt2);
|
||||
|
||||
String toElementText(String paramString);
|
||||
|
||||
String getEncoding();
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
public final class XMLEscapeASCII extends XMLEscapeBase implements XMLEscape {
|
||||
public static final XMLEscape ASCII_ESCAPE = new XMLEscapeASCII();
|
||||
|
||||
private static final String ENCODING = "ASCII";
|
||||
|
||||
private XMLEscapeASCII() {
|
||||
super("ASCII");
|
||||
}
|
||||
|
||||
public String toAttributeValue(char[] ch, int off, int len) {
|
||||
StringBuffer out = new StringBuffer(len + len / 10);
|
||||
for (int i = off; i < off + len; i++) {
|
||||
if (ch[i] < ' ') {
|
||||
if (ch[i] == '\t' || ch[i] == '\n' || ch[i] == '\r') {
|
||||
out.append(ch[i]);
|
||||
} else {
|
||||
doNothing();
|
||||
}
|
||||
} else if (ch[i] < '\u0080') {
|
||||
switch (ch[i]) {
|
||||
case '&':
|
||||
out.append("&");
|
||||
break;
|
||||
case '<':
|
||||
out.append("<");
|
||||
break;
|
||||
case '"':
|
||||
out.append(""");
|
||||
break;
|
||||
case '\'':
|
||||
out.append("'");
|
||||
break;
|
||||
default:
|
||||
out.append(ch[i]);
|
||||
break;
|
||||
}
|
||||
} else if (ch[i] < '\u00A0') {
|
||||
doNothing();
|
||||
} else {
|
||||
out.append("&#x").append(ch[i]).append(';');
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public String toElementText(char[] ch, int off, int len) {
|
||||
StringBuffer out = new StringBuffer(len + len / 10);
|
||||
for (int i = off; i < off + len; i++) {
|
||||
if (ch[i] < ' ') {
|
||||
if (ch[i] == '\t' || ch[i] == '\n' || ch[i] == '\r') {
|
||||
out.append(ch[i]);
|
||||
} else {
|
||||
doNothing();
|
||||
}
|
||||
} else if (ch[i] < '\u0080') {
|
||||
switch (ch[i]) {
|
||||
case '&':
|
||||
out.append("&");
|
||||
break;
|
||||
case '<':
|
||||
out.append("<");
|
||||
break;
|
||||
default:
|
||||
out.append(ch[i]);
|
||||
break;
|
||||
}
|
||||
} else if (ch[i] < '\u00A0') {
|
||||
doNothing();
|
||||
} else {
|
||||
out.append("&#x").append(ch[i]).append(';');
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private void doNothing() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
abstract class XMLEscapeBase implements XMLEscape {
|
||||
private final String encoding;
|
||||
|
||||
XMLEscapeBase(String encoding) {
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
public final String toAttributeValue(String value) {
|
||||
if (value == null || "".equals(value))
|
||||
return value;
|
||||
return toAttributeValue(value.toCharArray(), 0, value.length());
|
||||
}
|
||||
|
||||
public final String toElementText(String value) {
|
||||
if (value == null || "".equals(value))
|
||||
return value;
|
||||
return toElementText(value.toCharArray(), 0, value.length());
|
||||
}
|
||||
|
||||
public final String getEncoding() {
|
||||
return this.encoding;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
public final class XMLEscapeFactory {
|
||||
public static XMLEscape getInstance(String encoding) {
|
||||
if ("utf-8".equals(encoding))
|
||||
return XMLEscapeUTF8.UTF8_ESCAPE;
|
||||
if ("UTF-8".equals(encoding))
|
||||
return XMLEscapeUTF8.UTF8_ESCAPE;
|
||||
if ("ASCII".equals(encoding))
|
||||
return XMLEscapeASCII.ASCII_ESCAPE;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
public final class XMLEscapeUTF8 extends XMLEscapeBase implements XMLEscape {
|
||||
public static final XMLEscape UTF8_ESCAPE = new XMLEscapeUTF8();
|
||||
|
||||
private static final String ENCODING = "utf-8";
|
||||
|
||||
private XMLEscapeUTF8() {
|
||||
super("utf-8");
|
||||
}
|
||||
|
||||
public String toAttributeValue(char[] ch, int off, int len) {
|
||||
StringBuffer out = new StringBuffer(len + len / 10);
|
||||
for (int i = off; i < off + len; i++) {
|
||||
switch (ch[i]) {
|
||||
case '\000':
|
||||
case '\001':
|
||||
case '\002':
|
||||
case '\003':
|
||||
case '\004':
|
||||
case '\005':
|
||||
case '\006':
|
||||
case '\007':
|
||||
case '\b':
|
||||
case '\013':
|
||||
case '\f':
|
||||
case '\016':
|
||||
case '\017':
|
||||
case '\020':
|
||||
case '\021':
|
||||
case '\022':
|
||||
case '\023':
|
||||
case '\024':
|
||||
case '\025':
|
||||
case '\026':
|
||||
case '\027':
|
||||
case '\030':
|
||||
case '\031':
|
||||
case '\032':
|
||||
case '\033':
|
||||
case '\034':
|
||||
case '\035':
|
||||
case '\036':
|
||||
case '\037':
|
||||
case '\u007F':
|
||||
break;
|
||||
case '&':
|
||||
out.append("&");
|
||||
break;
|
||||
case '<':
|
||||
out.append("<");
|
||||
break;
|
||||
case '"':
|
||||
out.append(""");
|
||||
break;
|
||||
case '\'':
|
||||
out.append("'");
|
||||
break;
|
||||
default:
|
||||
out.append(ch[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public String toElementText(char[] ch, int off, int len) {
|
||||
StringBuffer out = new StringBuffer(len + len / 10);
|
||||
for (int i = off; i < off + len; i++) {
|
||||
switch (ch[i]) {
|
||||
case '\000':
|
||||
case '\001':
|
||||
case '\002':
|
||||
case '\003':
|
||||
case '\004':
|
||||
case '\005':
|
||||
case '\006':
|
||||
case '\007':
|
||||
case '\b':
|
||||
case '\013':
|
||||
case '\f':
|
||||
case '\016':
|
||||
case '\017':
|
||||
case '\020':
|
||||
case '\021':
|
||||
case '\022':
|
||||
case '\023':
|
||||
case '\024':
|
||||
case '\025':
|
||||
case '\026':
|
||||
case '\027':
|
||||
case '\030':
|
||||
case '\031':
|
||||
case '\032':
|
||||
case '\033':
|
||||
case '\034':
|
||||
case '\035':
|
||||
case '\036':
|
||||
case '\037':
|
||||
case '\u007F':
|
||||
break;
|
||||
case '&':
|
||||
out.append("&");
|
||||
break;
|
||||
case '<':
|
||||
out.append("<");
|
||||
break;
|
||||
default:
|
||||
out.append(ch[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface XMLEscapeWriter {
|
||||
void writeAttValue(char[] paramArrayOfchar, int paramInt1, int paramInt2) throws IOException;
|
||||
|
||||
void writeAttValue(String paramString) throws IOException;
|
||||
|
||||
void writeText(char[] paramArrayOfchar, int paramInt1, int paramInt2) throws IOException;
|
||||
|
||||
void writeText(String paramString) throws IOException;
|
||||
|
||||
void writeText(char paramChar) throws IOException;
|
||||
|
||||
String getEncoding();
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
public final class XMLEscapeWriterASCII extends XMLEscapeWriterBase implements XMLEscapeWriter {
|
||||
private static final String ENCODING = "ASCII";
|
||||
|
||||
public XMLEscapeWriterASCII(Writer writer) throws NullPointerException {
|
||||
super(writer, "ASCII");
|
||||
}
|
||||
|
||||
public void writeAttValue(char[] ch, int off, int len) throws IOException {
|
||||
char c = ' ';
|
||||
for (int i = off; i < off + len; i++) {
|
||||
c = ch[i];
|
||||
if (c == '<') {
|
||||
this.w.write("<");
|
||||
} else if (c == '>') {
|
||||
this.w.write(">");
|
||||
} else if (c == '&') {
|
||||
this.w.write("&");
|
||||
} else if (c == '"') {
|
||||
this.w.write(""");
|
||||
} else if (c == '\'') {
|
||||
this.w.write("'");
|
||||
} else if (c > 'ÿ') {
|
||||
this.w.write("&#" + c + ";");
|
||||
} else if (c == '\n' || c == '\r' || c == '\t') {
|
||||
this.w.write(c);
|
||||
} else if (c < ' ') {
|
||||
doNothing();
|
||||
} else if (c >= '\u007F' && c < '\u00A0') {
|
||||
doNothing();
|
||||
} else {
|
||||
this.w.write(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeText(char c) throws IOException {
|
||||
if (c == '<') {
|
||||
this.w.write("<");
|
||||
} else if (c == '>') {
|
||||
this.w.write(">");
|
||||
} else if (c == '&') {
|
||||
this.w.write("&");
|
||||
} else if (c == '"') {
|
||||
this.w.write(""");
|
||||
} else if (c == '\'') {
|
||||
this.w.write("'");
|
||||
} else if (c > 'ÿ') {
|
||||
this.w.write("&#" + c + ";");
|
||||
} else if (c == '\n' || c == '\r' || c == '\t') {
|
||||
this.w.write(c);
|
||||
} else if (c < ' ') {
|
||||
doNothing();
|
||||
} else if (c >= '\u007F' && c < '\u00A0') {
|
||||
doNothing();
|
||||
} else {
|
||||
this.w.write(c);
|
||||
}
|
||||
}
|
||||
|
||||
private static void doNothing() {}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue