first commit

This commit is contained in:
MaddoScientisto 2026-03-14 20:04:39 +01:00
commit 4d332ef662
27586 changed files with 3281783 additions and 0 deletions

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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());
}
}

View 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;
}
}

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -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));
}
}

View file

@ -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));
}
}

View file

@ -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];
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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));
}
}

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -0,0 +1,5 @@
package com.topologi.diffx.config;
public enum TextGranularity {
CHARACTER, WORD, TEXT;
}

View file

@ -0,0 +1,5 @@
package com.topologi.diffx.config;
public enum WhiteSpaceProcessing {
IGNORE, PRESERVE, COMPARE;
}

View file

@ -0,0 +1,9 @@
package com.topologi.diffx.event;
public interface AttributeEvent extends DiffXEvent {
String getName();
String getValue();
String getURI();
}

View file

@ -0,0 +1,11 @@
package com.topologi.diffx.event;
public interface CloseElementEvent extends DiffXEvent {
String getName();
String getURI();
OpenElementEvent getOpenElement();
boolean match(OpenElementEvent paramOpenElementEvent);
}

View file

@ -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);
}

View file

@ -0,0 +1,7 @@
package com.topologi.diffx.event;
public interface OpenElementEvent extends DiffXEvent {
String getName();
String getURI();
}

View file

@ -0,0 +1,5 @@
package com.topologi.diffx.event;
public interface TextEvent extends DiffXEvent {
String getCharacters();
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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));
}
}

View file

@ -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() + '"';
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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) {}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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() + '"';
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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));
}
}
}

View file

@ -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 "???";
}
}

View file

@ -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));
}
}
}

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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();
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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";
}

View file

@ -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);
}
}

View file

@ -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.");
}
}

View file

@ -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.");
}
}

View file

@ -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.");
}
}

View file

@ -0,0 +1,7 @@
package com.topologi.diffx.xml;
public interface XMLFormattable {
StringBuffer toXML(StringBuffer paramStringBuffer) throws NullPointerException;
String toXML();
}

View file

@ -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();
}
}

View file

@ -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;
}
}
}

View file

@ -0,0 +1,3 @@
package com.topologi.diffx.xml;
public interface XMLSerializable {}

View file

@ -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);
}
}
}

View file

@ -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() {}
}

View file

@ -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);
}
}

View file

@ -0,0 +1,7 @@
package com.topologi.diffx.xml;
import java.io.IOException;
public interface XMLWritable {
void toXML(XMLWriter paramXMLWriter) throws IOException;
}

View file

@ -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;
}

View file

@ -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() {}
}

View file

@ -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;
}
}
}

View file

@ -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 : "";
}
}
}

View file

@ -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();
}

View file

@ -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();
}
}

View file

@ -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();
}

View file

@ -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("&amp;");
break;
case '<':
out.append("&lt;");
break;
case '"':
out.append("&quot;");
break;
case '\'':
out.append("&apos;");
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("&amp;");
break;
case '<':
out.append("&lt;");
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() {}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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("&amp;");
break;
case '<':
out.append("&lt;");
break;
case '"':
out.append("&quot;");
break;
case '\'':
out.append("&apos;");
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("&amp;");
break;
case '<':
out.append("&lt;");
break;
default:
out.append(ch[i]);
break;
}
}
return out.toString();
}
}

View file

@ -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();
}

View file

@ -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("&lt;");
} else if (c == '>') {
this.w.write("&gt;");
} else if (c == '&') {
this.w.write("&amp;");
} else if (c == '"') {
this.w.write("&quot;");
} else if (c == '\'') {
this.w.write("&apos;");
} 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("&lt;");
} else if (c == '>') {
this.w.write("&gt;");
} else if (c == '&') {
this.w.write("&amp;");
} else if (c == '"') {
this.w.write("&quot;");
} else if (c == '\'') {
this.w.write("&apos;");
} 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() {}
}

View file

@ -0,0 +1,38 @@
package com.topologi.diffx.xml.esc;
import java.io.IOException;
import java.io.Writer;
abstract class XMLEscapeWriterBase implements XMLEscapeWriter {
private final String encoding;
final Writer w;
XMLEscapeWriterBase(Writer writer, String encoding) {
if (writer == null)
throw new NullPointerException("Cannot construct XML escape for null writer.");
this.w = writer;
this.encoding = encoding;
}
public final void writeAttValue(String value) throws IOException {
if (value == null || "".equals(value))
return;
writeAttValue(value.toCharArray(), 0, value.length());
}
public final void writeText(String value) throws IOException {
if (value == null || "".equals(value))
return;
writeText(value.toCharArray(), 0, value.length());
}
public void writeText(char[] ch, int off, int len) throws IOException {
for (int i = off; i < off + len; i++)
writeText(ch[i]);
}
public final String getEncoding() {
return this.encoding;
}
}

View file

@ -0,0 +1,66 @@
package com.topologi.diffx.xml.esc;
import java.io.IOException;
import java.io.Writer;
public final class XMLEscapeWriterUTF8 extends XMLEscapeWriterBase implements XMLEscapeWriter {
private static final String ENCODING = "utf-8";
public XMLEscapeWriterUTF8(Writer writer) throws NullPointerException {
super(writer, "utf-8");
}
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("&lt;");
} else if (c == '>') {
this.w.write("&gt;");
} else if (c == '&') {
this.w.write("&amp;");
} else if (c == '"') {
this.w.write("&quot;");
} else if (c == '\'') {
this.w.write("&apos;");
} 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("&lt;");
} else if (c == '>') {
this.w.write("&gt;");
} else if (c == '&') {
this.w.write("&amp;");
} else if (c == '"') {
this.w.write("&quot;");
} else if (c == '\'') {
this.w.write("&apos;");
} 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() {}
}

View file

@ -0,0 +1,72 @@
package com.topologi.diffx.xml.sax;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
public final class ReporterHandlerProxy implements ContentHandler {
private final ContentHandler handler;
public ReporterHandlerProxy(ContentHandler handler) {
this.handler = handler;
}
public void characters(char[] ch, int start, int length) throws SAXException {
System.err.println("characters(\"" + new String(ch, start, length) + "\");");
this.handler.characters(ch, start, length);
}
public void startElement(String uri, String local, String qName, Attributes atts) throws SAXException {
System.err.println("startElement(\"" + uri + "\", \"" + local + "\", \"" + qName + "\");");
this.handler.startElement(uri, local, qName, atts);
}
public void endElement(String uri, String local, String qName) throws SAXException {
System.err.println("endElement(\"" + uri + "\", \"" + local + "\", \"" + qName + "\");");
this.handler.endElement(uri, local, qName);
}
public void startPrefixMapping(String prefix, String uri) throws SAXException {
System.err.println("startPrefixMapping(\"" + prefix + "\", \"" + uri + "\");");
this.handler.startPrefixMapping(prefix, uri);
}
public void endPrefixMapping(String prefix) throws SAXException {
System.err.println("endPrefixMapping(\"" + prefix + "\");");
this.handler.endPrefixMapping(prefix);
}
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
System.err.println("ignorableWhitespace(\"" + new String(ch, start, length) + "\");");
this.handler.ignorableWhitespace(ch, start, length);
}
public void processingInstruction(String target, String data) throws SAXException {
System.err.println("processingInstruction(\"" + target + "\", \"" + data + "\");");
this.handler.processingInstruction(target, data);
}
public void skippedEntity(String name) throws SAXException {
System.err.println("skippedEntity(\"" + name + "\");");
this.handler.skippedEntity(name);
}
public void setDocumentLocator(Locator locator) {
this.handler.setDocumentLocator(locator);
}
public void startDocument() throws SAXException {
System.err.println("startDocument();");
this.handler.startDocument();
}
public void endDocument() throws SAXException {
System.err.println("endDocument();");
this.handler.endDocument();
}
public ContentHandler getContentHandler() {
return this.handler;
}
}

Some files were not shown because too many files have changed in this diff Show more