first commit
This commit is contained in:
commit
4d332ef662
27586 changed files with 3281783 additions and 0 deletions
|
|
@ -0,0 +1,19 @@
|
|||
package com.topologi.diffx;
|
||||
|
||||
public class DiffXException extends Exception {
|
||||
private static final long serialVersionUID = 3572025323967229569L;
|
||||
|
||||
public DiffXException() {}
|
||||
|
||||
public DiffXException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DiffXException(Exception ex) {
|
||||
super(ex);
|
||||
}
|
||||
|
||||
public DiffXException(String message, Exception ex) {
|
||||
super(message, ex);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
package com.topologi.diffx;
|
||||
|
||||
import com.topologi.diffx.algorithm.DiffXAlgorithm;
|
||||
import com.topologi.diffx.algorithm.DiffXFitopsy;
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.impl.CommentEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.format.SmartXMLFormatter;
|
||||
import com.topologi.diffx.load.DOMRecorder;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import com.topologi.diffx.sequence.SequenceSlicer;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.eclipse.compare.EventSequenceComparator;
|
||||
import org.eclipse.compare.rangedifferencer.RangeDifference;
|
||||
import org.eclipse.compare.rangedifferencer.RangeDifferencer;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
public class Docx4jDriver {
|
||||
public static final boolean debug = false;
|
||||
|
||||
public static void log(String message, boolean force) {
|
||||
if (force)
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
public static void log(String message) {
|
||||
log(message, false);
|
||||
}
|
||||
|
||||
public static void formatEventSequence(EventSequence eventSequence, DiffXFormatter formatter) throws NullPointerException, IOException {
|
||||
List<DiffXEvent> sequence = eventSequence.events();
|
||||
DiffXEvent x = null;
|
||||
for (int i = 0; i < sequence.size(); i++) {
|
||||
x = sequence.get(i);
|
||||
formatter.format(x);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addToPrefixMapping(PrefixMapping to, PrefixMapping others) throws NullPointerException {
|
||||
for (Enumeration<String> e = others.getURIs(); e.hasMoreElements(); ) {
|
||||
String key = e.nextElement();
|
||||
to.add(key, others.getPrefix(key));
|
||||
}
|
||||
}
|
||||
|
||||
public static void mainDiff(EventSequence seq1, EventSequence seq2, SmartXMLFormatter formatter, DiffXConfig config) throws DiffXException, IOException {
|
||||
formatter.declarePrefixMapping(seq1.getPrefixMapping());
|
||||
formatter.declarePrefixMapping(seq2.getPrefixMapping());
|
||||
if (config != null)
|
||||
formatter.setConfig(config);
|
||||
SequenceSlicer slicer = new SequenceSlicer(seq1, seq2);
|
||||
slicer.slice();
|
||||
slicer.formatStart(formatter);
|
||||
DiffXAlgorithm df = new DiffXFitopsy(seq1, seq2);
|
||||
df.process(formatter);
|
||||
slicer.formatEnd(formatter);
|
||||
}
|
||||
|
||||
public static void diff(Node xml1, Node xml2, Writer out) throws DiffXException, IOException {
|
||||
try {
|
||||
DiffXConfig diffxConfig = new DiffXConfig();
|
||||
diffxConfig.setIgnoreWhiteSpace(false);
|
||||
diffxConfig.setPreserveWhiteSpace(true);
|
||||
log(xml1.getNodeName());
|
||||
log("" + xml1.getChildNodes().getLength());
|
||||
log(xml2.getNodeName());
|
||||
log("" + xml2.getChildNodes().getLength());
|
||||
if (!xml1.getNodeName().equals(xml2.getNodeName()) || (xml1.getChildNodes().getLength() <= 3 && xml2.getChildNodes().getLength() <= 3)) {
|
||||
log("Skipping top level LCS");
|
||||
Main.diff(xml1, xml2, out, diffxConfig);
|
||||
out.close();
|
||||
return;
|
||||
}
|
||||
DOMRecorder loader = new DOMRecorder();
|
||||
loader.setConfig(diffxConfig);
|
||||
log("top level LCS - creating EventSequences...");
|
||||
List<EventSequence> leftES = new ArrayList<EventSequence>();
|
||||
for (int i = 0; i < xml1.getChildNodes().getLength(); i++) {
|
||||
if (xml1.getChildNodes().item(i).getNodeType() != 3) {
|
||||
Element e = (Element)xml1.getChildNodes().item(i);
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpc", "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:a14", "http://schemas.microsoft.com/office/drawing/2010/main");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:m", "http://schemas.openxmlformats.org/officeDocument/2006/math");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:mc", "http://schemas.openxmlformats.org/markup-compatibility/2006");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:o", "urn:schemas-microsoft-com:office:office");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:pic", "http://schemas.openxmlformats.org/drawingml/2006/picture");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:v", "urn:schemas-microsoft-com:vml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w10", "urn:schemas-microsoft-com:office:word");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w14", "http://schemas.microsoft.com/office/word/2010/wordml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w15", "http://schemas.microsoft.com/office/word/2012/wordml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wne", "http://schemas.microsoft.com/office/word/2006/wordml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wp", "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wp14", "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpc", "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpg", "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpi", "http://schemas.microsoft.com/office/word/2010/wordprocessingInk");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wps", "http://schemas.microsoft.com/office/word/2010/wordprocessingShape");
|
||||
leftES.add(loader.process(e));
|
||||
}
|
||||
}
|
||||
EventSequenceComparator leftESC = new EventSequenceComparator(leftES);
|
||||
List<EventSequence> rightES = new ArrayList<EventSequence>();
|
||||
for (int j = 0; j < xml2.getChildNodes().getLength(); j++) {
|
||||
if (xml2.getChildNodes().item(j).getNodeType() != 3) {
|
||||
Element e = (Element)xml2.getChildNodes().item(j);
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpc", "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:a14", "http://schemas.microsoft.com/office/drawing/2010/main");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:m", "http://schemas.openxmlformats.org/officeDocument/2006/math");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:mc", "http://schemas.openxmlformats.org/markup-compatibility/2006");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:o", "urn:schemas-microsoft-com:office:office");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:pic", "http://schemas.openxmlformats.org/drawingml/2006/picture");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:v", "urn:schemas-microsoft-com:vml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w10", "urn:schemas-microsoft-com:office:word");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w14", "http://schemas.microsoft.com/office/word/2010/wordml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:w15", "http://schemas.microsoft.com/office/word/2012/wordml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wne", "http://schemas.microsoft.com/office/word/2006/wordml");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wp", "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wp14", "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpc", "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpg", "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wpi", "http://schemas.microsoft.com/office/word/2010/wordprocessingInk");
|
||||
e.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wps", "http://schemas.microsoft.com/office/word/2010/wordprocessingShape");
|
||||
rightES.add(loader.process(e));
|
||||
}
|
||||
}
|
||||
EventSequenceComparator rightESC = new EventSequenceComparator(rightES);
|
||||
log("top level LCS - determining top level LCS...");
|
||||
RangeDifference[] rd = RangeDifferencer.findDifferences(leftESC, rightESC);
|
||||
SmartXMLFormatter formatter = new SmartXMLFormatter(out);
|
||||
formatter.setConfig(diffxConfig);
|
||||
String rootNodeName = xml1.getNodeName();
|
||||
openResult(rootNodeName, out);
|
||||
if (rd.length == 0) {
|
||||
log("top level LCS done; there are no differences!");
|
||||
addComment("No differences", formatter);
|
||||
for (EventSequence es : leftES)
|
||||
formatEventSequence(es, formatter);
|
||||
closeResult(rootNodeName, out);
|
||||
return;
|
||||
}
|
||||
for (int k = 0; k < rd.length; k++) {
|
||||
RangeDifference rdi = rd[k];
|
||||
log(rdi.kindString() + " left " + rdi.leftStart() + "," + rdi.leftLength() + " right " + rdi.rightStart() + "," + rdi.rightLength());
|
||||
}
|
||||
log("top level LCS done; now performing child actions ...");
|
||||
int leftIdx = 0;
|
||||
for (int m = 0; m < rd.length; m++) {
|
||||
RangeDifference rdi = rd[m];
|
||||
if (rdi.leftStart() > leftIdx) {
|
||||
for (int i2 = leftIdx; i2 < rdi.leftStart(); i2++) {
|
||||
addComment("Adding same", formatter);
|
||||
formatter.declarePrefixMapping(leftESC.getItem(i2).getPrefixMapping());
|
||||
formatEventSequence(leftESC.getItem(i2), formatter);
|
||||
addComment(".. Adding same done ", formatter);
|
||||
}
|
||||
leftIdx = rdi.leftStart();
|
||||
}
|
||||
EventSequence seq1 = new EventSequence();
|
||||
for (int n = rdi.leftStart(); n < rdi.leftEnd(); n++) {
|
||||
if (rdi.kind() == 2) {
|
||||
seq1.addSequence(leftESC.getItem(n));
|
||||
PrefixMapping existingPM = leftESC.getItem(n).getPrefixMapping();
|
||||
addToPrefixMapping(seq1.getPrefixMapping(), existingPM);
|
||||
} else {
|
||||
formatter.declarePrefixMapping(leftESC.getItem(n).getPrefixMapping());
|
||||
addComment("Adding same II", formatter);
|
||||
formatEventSequence(leftESC.getItem(n), formatter);
|
||||
addComment(".. Adding same done", formatter);
|
||||
}
|
||||
}
|
||||
EventSequence seq2 = new EventSequence();
|
||||
for (int i1 = rdi.rightStart(); i1 < rdi.rightEnd(); i1++) {
|
||||
if (rdi.kind() == 2) {
|
||||
seq2.addSequence(rightESC.getItem(i1));
|
||||
PrefixMapping existingPM = rightESC.getItem(i1).getPrefixMapping();
|
||||
addToPrefixMapping(seq2.getPrefixMapping(), existingPM);
|
||||
}
|
||||
}
|
||||
leftIdx = rdi.leftEnd();
|
||||
addComment("Differencing", formatter);
|
||||
if (seq1.size() + seq2.size() < 5000) {
|
||||
mainDiff(seq1, seq2, formatter, diffxConfig);
|
||||
} else {
|
||||
for (int i3 = 0; i3 < seq1.size(); i3++)
|
||||
formatter.delete(seq1.getEvent(i3));
|
||||
for (int i2 = 0; i2 < seq2.size(); i2++)
|
||||
formatter.insert(seq2.getEvent(i2));
|
||||
}
|
||||
addComment(".. Differencing done", formatter);
|
||||
}
|
||||
addComment("Adding tail", formatter);
|
||||
if (rd.length > 0)
|
||||
for (int n = rd[rd.length - 1].leftEnd(); n < leftESC.getRangeCount(); n++)
|
||||
formatEventSequence(leftESC.getItem(n), formatter);
|
||||
closeResult(rootNodeName, out);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
e.printStackTrace();
|
||||
throw new DiffXException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addComment(String message, SmartXMLFormatter formatter) throws IOException {
|
||||
CommentEvent ce = new CommentEvent(message);
|
||||
formatter.format(ce);
|
||||
}
|
||||
|
||||
public static void openResult(String nodename, Writer out) throws IOException {
|
||||
out.append("<" + nodename + " xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"" + " xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\"" + " xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\"" + " xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"" + " xmlns:v=\"urn:schemas-microsoft-com:vml\"" + " xmlns:w10=\"urn:schemas-microsoft-com:office:word\"" + " xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\"" + " xmlns:dfx=\"" + "http://www.topologi.com/2005/Diff-X" + "\"" + " xmlns:del=\"" + "http://www.topologi.com/2005/Diff-X/Delete" + "\"" + " xmlns:ins=\"" + "http://www.topologi.com/2005/Diff-X" + "\"" + " >");
|
||||
}
|
||||
|
||||
public static void closeResult(String nodename, Writer out) throws IOException {
|
||||
out.append("</" + nodename + ">");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Writer diffxResult = new StringWriter();
|
||||
try {
|
||||
long startTime = System.currentTimeMillis();
|
||||
diff(getDocument(new File("1L.xml")).getDocumentElement(), getDocument(new File("1R.xml")).getDocumentElement(), diffxResult);
|
||||
diffxResult.close();
|
||||
long endTime = System.currentTimeMillis();
|
||||
long duration = endTime - startTime;
|
||||
System.out.println(duration + "ms");
|
||||
System.out.println(diffxResult.toString());
|
||||
} catch (Exception exc) {
|
||||
exc.printStackTrace();
|
||||
diffxResult = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Document getDocument(File f) throws Exception {
|
||||
DocumentBuilder db = XmlUtils.getNewDocumentBuilder();
|
||||
return db.parse(f);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package com.topologi.diffx;
|
||||
|
||||
import com.topologi.diffx.algorithm.DiffXAlgorithm;
|
||||
import com.topologi.diffx.algorithm.GuanoAlgorithm;
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
import com.topologi.diffx.config.WhiteSpaceProcessing;
|
||||
import com.topologi.diffx.format.SafeXMLFormatter;
|
||||
import com.topologi.diffx.load.DOMRecorder;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import com.topologi.diffx.sequence.SequenceSlicer;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public final class Extension {
|
||||
private static final Map<String, String> BUILDERS = new Hashtable<String, String>();
|
||||
|
||||
public static Node diff(Node xml1, Node xml2, String whitespace, String granularity) throws DiffXException, IOException {
|
||||
DiffXConfig config = toConfig(whitespace, granularity);
|
||||
DOMRecorder loader = new DOMRecorder();
|
||||
loader.setConfig(config);
|
||||
EventSequence seq1 = loader.process(xml1);
|
||||
EventSequence seq2 = loader.process(xml2);
|
||||
if (seq1.size() == 0 && seq1.size() == 0)
|
||||
return null;
|
||||
StringWriter out = new StringWriter();
|
||||
diff(seq1, seq2, out, config);
|
||||
try {
|
||||
String factory = getFactoryClass(xml1, xml2);
|
||||
Node node = toNode(out.toString(), config, factory);
|
||||
return node;
|
||||
} catch (Exception ex) {
|
||||
throw new DiffXException("Could not generate Node from Diff-X result", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void diff(EventSequence seq1, EventSequence seq2, Writer out, DiffXConfig config) throws DiffXException, IOException {
|
||||
SafeXMLFormatter formatter = new SafeXMLFormatter(out);
|
||||
formatter.declarePrefixMapping(seq1.getPrefixMapping());
|
||||
formatter.declarePrefixMapping(seq2.getPrefixMapping());
|
||||
if (config != null)
|
||||
formatter.setConfig(config);
|
||||
SequenceSlicer slicer = new SequenceSlicer(seq1, seq2);
|
||||
slicer.slice();
|
||||
slicer.formatStart(formatter);
|
||||
DiffXAlgorithm df = new GuanoAlgorithm(seq1, seq2);
|
||||
df.process(formatter);
|
||||
slicer.formatEnd(formatter);
|
||||
}
|
||||
|
||||
private static DiffXConfig toConfig(String whitespace, String granularity) {
|
||||
WhiteSpaceProcessing ws = WhiteSpaceProcessing.valueOf(whitespace);
|
||||
TextGranularity tg = TextGranularity.valueOf(granularity);
|
||||
return new DiffXConfig(ws, tg);
|
||||
}
|
||||
|
||||
private static Node toNode(String xml, DiffXConfig config, String factory) throws IOException, ParserConfigurationException, SAXException {
|
||||
Document document = XmlUtils.getNewDocumentBuilder().parse(new InputSource(new StringReader(xml)));
|
||||
return document.getDocumentElement();
|
||||
}
|
||||
|
||||
private static String getFactoryClass(Node xml1, Node xml2) {
|
||||
Package pkg = (xml1 != null) ? xml1.getClass().getPackage() : ((xml2 != null) ? xml2.getClass().getPackage() : null);
|
||||
return BUILDERS.get(pkg.getName());
|
||||
}
|
||||
}
|
||||
263
rus/WEB-INF/lib/docx4j-3.2.1_src/com/topologi/diffx/Main.java
Normal file
263
rus/WEB-INF/lib/docx4j-3.2.1_src/com/topologi/diffx/Main.java
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
package com.topologi.diffx;
|
||||
|
||||
import com.topologi.diffx.algorithm.DiffXAlgorithm;
|
||||
import com.topologi.diffx.algorithm.DiffXFitWesyma;
|
||||
import com.topologi.diffx.algorithm.DiffXFitopsy;
|
||||
import com.topologi.diffx.algorithm.DiffXFitsy;
|
||||
import com.topologi.diffx.algorithm.DiffXKumarRangan;
|
||||
import com.topologi.diffx.algorithm.GuanoAlgorithm;
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
import com.topologi.diffx.config.WhiteSpaceProcessing;
|
||||
import com.topologi.diffx.format.BasicXMLFormatter;
|
||||
import com.topologi.diffx.format.ConvenientXMLFormatter;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.format.SafeXMLFormatter;
|
||||
import com.topologi.diffx.format.SmartXMLFormatter;
|
||||
import com.topologi.diffx.format.StrictXMLFormatter;
|
||||
import com.topologi.diffx.format.XMLDiffXFormatter;
|
||||
import com.topologi.diffx.load.DOMRecorder;
|
||||
import com.topologi.diffx.load.Recorder;
|
||||
import com.topologi.diffx.load.SAXRecorder;
|
||||
import com.topologi.diffx.load.TextRecorder;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import com.topologi.diffx.sequence.SequenceSlicer;
|
||||
import com.topologi.diffx.util.CommandLine;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
public final class Main {
|
||||
public static boolean equivalent(File xml1, File xml2) throws DiffXException, IOException {
|
||||
Recorder recorder = new SAXRecorder();
|
||||
EventSequence seq0 = recorder.process(xml1);
|
||||
EventSequence seq1 = recorder.process(xml2);
|
||||
return seq0.equals(seq1);
|
||||
}
|
||||
|
||||
public static boolean equivalent(InputStream xml1, InputStream xml2) throws DiffXException, IOException {
|
||||
SAXRecorder recorder = new SAXRecorder();
|
||||
EventSequence seq0 = recorder.process(new InputSource(xml1));
|
||||
EventSequence seq1 = recorder.process(new InputSource(xml2));
|
||||
return seq0.equals(seq1);
|
||||
}
|
||||
|
||||
public static boolean equivalent(Reader xml1, Reader xml2) throws DiffXException, IOException {
|
||||
SAXRecorder recorder = new SAXRecorder();
|
||||
EventSequence seq0 = recorder.process(new InputSource(xml1));
|
||||
EventSequence seq1 = recorder.process(new InputSource(xml2));
|
||||
return seq0.equals(seq1);
|
||||
}
|
||||
|
||||
public static void diff(Node xml1, Node xml2, Writer out, DiffXConfig config) throws DiffXException, IOException {
|
||||
DOMRecorder loader = new DOMRecorder();
|
||||
if (config != null)
|
||||
loader.setConfig(config);
|
||||
EventSequence seq1 = loader.process(xml1);
|
||||
EventSequence seq2 = loader.process(xml2);
|
||||
diff(seq1, seq2, out, config);
|
||||
}
|
||||
|
||||
public static void diff(NodeList xml1, NodeList xml2, Writer out, DiffXConfig config) throws DiffXException, IOException {
|
||||
DOMRecorder loader = new DOMRecorder();
|
||||
if (config != null)
|
||||
loader.setConfig(config);
|
||||
EventSequence seq1 = loader.process(xml1);
|
||||
EventSequence seq2 = loader.process(xml2);
|
||||
diff(seq1, seq2, out, config);
|
||||
}
|
||||
|
||||
public static void diff(Reader xml1, Reader xml2, Writer out, DiffXConfig config) throws DiffXException, IOException {
|
||||
SAXRecorder recorder = new SAXRecorder();
|
||||
if (config != null)
|
||||
recorder.setConfig(config);
|
||||
EventSequence seq1 = recorder.process(new InputSource(xml1));
|
||||
EventSequence seq2 = recorder.process(new InputSource(xml2));
|
||||
diff(seq1, seq2, out, config);
|
||||
}
|
||||
|
||||
public static void diff(Reader xml1, Reader xml2, Writer out) throws DiffXException, IOException {
|
||||
SAXRecorder recorder = new SAXRecorder();
|
||||
EventSequence seq1 = recorder.process(new InputSource(xml1));
|
||||
EventSequence seq2 = recorder.process(new InputSource(xml2));
|
||||
diff(seq1, seq2, out, new DiffXConfig());
|
||||
}
|
||||
|
||||
public static void diff(InputStream xml1, InputStream xml2, OutputStream out) throws DiffXException, IOException {
|
||||
SAXRecorder recorder = new SAXRecorder();
|
||||
EventSequence seq1 = recorder.process(new InputSource(xml1));
|
||||
EventSequence seq2 = recorder.process(new InputSource(xml2));
|
||||
diff(seq1, seq2, new OutputStreamWriter(out), new DiffXConfig());
|
||||
}
|
||||
|
||||
private static void diff(EventSequence seq1, EventSequence seq2, Writer out, DiffXConfig config) throws DiffXException, IOException {
|
||||
SafeXMLFormatter formatter = new SafeXMLFormatter(out);
|
||||
formatter.declarePrefixMapping(seq1.getPrefixMapping());
|
||||
formatter.declarePrefixMapping(seq2.getPrefixMapping());
|
||||
if (config != null)
|
||||
formatter.setConfig(config);
|
||||
SequenceSlicer slicer = new SequenceSlicer(seq1, seq2);
|
||||
slicer.slice();
|
||||
slicer.formatStart(formatter);
|
||||
DiffXAlgorithm df = new GuanoAlgorithm(seq1, seq2);
|
||||
df.process(formatter);
|
||||
slicer.formatEnd(formatter);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length < 2)
|
||||
usage();
|
||||
try {
|
||||
boolean profile = CommandLine.hasSwitch("-profile", args);
|
||||
boolean slice = !CommandLine.hasSwitch("-noslice", args);
|
||||
boolean quiet = CommandLine.hasSwitch("-quiet", args);
|
||||
File xml1 = new File(args[args.length - 2]);
|
||||
File xml2 = new File(args[args.length - 1]);
|
||||
long t0 = System.currentTimeMillis();
|
||||
Recorder recorder = getRecorder(args);
|
||||
EventSequence seq1 = recorder.process(xml1);
|
||||
EventSequence seq2 = recorder.process(xml2);
|
||||
long t1 = System.currentTimeMillis();
|
||||
if (profile)
|
||||
System.err.println("Loaded files in " + (t1 - t0) + "ms");
|
||||
DiffXConfig config = new DiffXConfig();
|
||||
config.setGranularity(getTextGranularity(args));
|
||||
config.setWhiteSpaceProcessing(getWhiteSpaceProcessing(args));
|
||||
if (!quiet)
|
||||
System.err.println("Whitespace processing: " + getTextGranularity(args) + " " + getWhiteSpaceProcessing(args));
|
||||
Writer out = new OutputStreamWriter(getOutput(args), "utf-8");
|
||||
DiffXFormatter formatter = getFormatter(args, out);
|
||||
if (formatter instanceof XMLDiffXFormatter) {
|
||||
((XMLDiffXFormatter)formatter).declarePrefixMapping(seq1.getPrefixMapping());
|
||||
((XMLDiffXFormatter)formatter).declarePrefixMapping(seq2.getPrefixMapping());
|
||||
}
|
||||
formatter.setConfig(config);
|
||||
SequenceSlicer slicer = new SequenceSlicer(seq1, seq2);
|
||||
if (slice) {
|
||||
slicer.slice();
|
||||
slicer.formatStart(formatter);
|
||||
}
|
||||
if (!quiet)
|
||||
System.err.println("Matrix: " + seq1.size() + "x" + seq2.size());
|
||||
DiffXAlgorithm df = getAlgorithm(args, seq1, seq2);
|
||||
df.process(formatter);
|
||||
if (slice)
|
||||
slicer.formatEnd(formatter);
|
||||
long t2 = System.currentTimeMillis();
|
||||
if (profile)
|
||||
System.err.println("Executed algorithm files in " + (t2 - t1) + "ms");
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void usage() {
|
||||
System.err.println("Compare the SAX events returned by two XML files.");
|
||||
System.err.println("usage:");
|
||||
System.err.println(" Main [options] xml_file1 xml_file2");
|
||||
System.err.println("where:");
|
||||
System.err.println(" xml_file1 = Path to the new XML file");
|
||||
System.err.println(" xml_file2 = Path to the old XML file");
|
||||
System.err.println("options:");
|
||||
System.err.println(" -profile Display profiling info");
|
||||
System.err.println(" -noslice Do not use slicing");
|
||||
System.err.println(" -o [output] The output file");
|
||||
System.err.println(" -L [loader] Choose a specific loader");
|
||||
System.err.println(" sax* | dom | text");
|
||||
System.err.println(" -A [algo] Choose a specific algorithm");
|
||||
System.err.println(" fitsy* | guano | fitopsy | kumar | wesyma");
|
||||
System.err.println(" -F [format] Choose a specific formatter");
|
||||
System.err.println(" smart* | basic | convenient | strict | short");
|
||||
System.err.println(" -W [wsp] Define whitespace processing");
|
||||
System.err.println(" preserve* | compare | ignore");
|
||||
System.err.println(" -G [granul] Define text diffing granularity");
|
||||
System.err.println(" word* | text | character");
|
||||
System.err.println(" * indicates option used by default.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private static Recorder getRecorder(String[] args) {
|
||||
String loaderArg = CommandLine.getParameter("-L", args);
|
||||
if (loaderArg == null || "sax".equals(loaderArg))
|
||||
return new SAXRecorder();
|
||||
if ("dom".equals(loaderArg))
|
||||
return new DOMRecorder();
|
||||
if ("text".equals(loaderArg))
|
||||
return new TextRecorder();
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static OutputStream getOutput(String[] args) throws FileNotFoundException {
|
||||
String outArg = CommandLine.getParameter("-o", args);
|
||||
if (outArg == null)
|
||||
return System.out;
|
||||
return new BufferedOutputStream(new FileOutputStream(outArg));
|
||||
}
|
||||
|
||||
private static DiffXAlgorithm getAlgorithm(String[] args, EventSequence seq1, EventSequence seq2) {
|
||||
String loaderArg = CommandLine.getParameter("-A", args);
|
||||
if (loaderArg == null || "fitsy".equals(loaderArg))
|
||||
return new DiffXFitsy(seq1, seq2);
|
||||
if ("guano".equals(loaderArg))
|
||||
return new GuanoAlgorithm(seq1, seq2);
|
||||
if ("fitopsy".equals(loaderArg))
|
||||
return new DiffXFitopsy(seq1, seq2);
|
||||
if ("kumar".equals(loaderArg))
|
||||
return new DiffXKumarRangan(seq1, seq2);
|
||||
if ("wesyma".equals(loaderArg))
|
||||
return new DiffXFitWesyma(seq1, seq2);
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static DiffXFormatter getFormatter(String[] args, Writer out) throws IOException {
|
||||
String formatArg = CommandLine.getParameter("-F", args);
|
||||
if (formatArg == null || "smart".equals(formatArg))
|
||||
return new SmartXMLFormatter(out);
|
||||
if ("convenient".equals(formatArg))
|
||||
return new ConvenientXMLFormatter(out);
|
||||
if ("basic".equals(formatArg))
|
||||
return new BasicXMLFormatter(out);
|
||||
if ("strict".equals(formatArg))
|
||||
return new StrictXMLFormatter(out);
|
||||
if ("short".equals(formatArg))
|
||||
return new StrictXMLFormatter(out);
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static WhiteSpaceProcessing getWhiteSpaceProcessing(String[] args) throws IOException {
|
||||
String formatArg = CommandLine.getParameter("-W", args);
|
||||
if (formatArg == null || "preserve".equals(formatArg))
|
||||
return WhiteSpaceProcessing.PRESERVE;
|
||||
if ("compare".equals(formatArg))
|
||||
return WhiteSpaceProcessing.COMPARE;
|
||||
if ("ignore".equals(formatArg))
|
||||
return WhiteSpaceProcessing.IGNORE;
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static TextGranularity getTextGranularity(String[] args) throws IOException {
|
||||
String formatArg = CommandLine.getParameter("-G", args);
|
||||
if (formatArg == null || "word".equals(formatArg))
|
||||
return TextGranularity.WORD;
|
||||
if ("text".equals(formatArg))
|
||||
return TextGranularity.TEXT;
|
||||
if ("character".equals(formatArg))
|
||||
return TextGranularity.CHARACTER;
|
||||
usage();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface DiffXAlgorithm {
|
||||
int length();
|
||||
|
||||
void process(DiffXFormatter paramDiffXFormatter) throws IOException;
|
||||
|
||||
EventSequence getFirstSequence();
|
||||
|
||||
EventSequence getSecondSequence();
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
|
||||
public abstract class DiffXAlgorithmBase implements DiffXAlgorithm {
|
||||
protected final EventSequence sequence1;
|
||||
|
||||
protected final EventSequence sequence2;
|
||||
|
||||
protected final int length1;
|
||||
|
||||
protected final int length2;
|
||||
|
||||
protected int length = -1;
|
||||
|
||||
public DiffXAlgorithmBase(EventSequence seq0, EventSequence seq1) {
|
||||
this.sequence1 = seq0;
|
||||
this.sequence2 = seq1;
|
||||
this.length1 = seq0.size();
|
||||
this.length2 = seq1.size();
|
||||
}
|
||||
|
||||
public final EventSequence getFirstSequence() {
|
||||
return this.sequence1;
|
||||
}
|
||||
|
||||
public final EventSequence getSecondSequence() {
|
||||
return this.sequence2;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
public final class DiffXFactory {
|
||||
private static final Class<?>[] ARGS = new Class<?>[] { EventSequence.class, EventSequence.class };
|
||||
|
||||
public static DiffXAlgorithm newAlgorithm(String className, EventSequence sequence1, EventSequence sequence2) throws FactoryException {
|
||||
DiffXAlgorithm algorithm = null;
|
||||
try {
|
||||
Class<DiffXAlgorithm> cls = (Class)Class.forName(className);
|
||||
Constructor<DiffXAlgorithm> cons = cls.getConstructor(ARGS);
|
||||
algorithm = cons.newInstance(sequence1, sequence2);
|
||||
} catch (Exception ex) {
|
||||
throw new FactoryException(ex);
|
||||
}
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static DiffXAlgorithm createDiffex(String className, EventSequence sequence1, EventSequence sequence2) throws FactoryException {
|
||||
return newAlgorithm(className, sequence1, sequence2);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class DiffXFitWesyma extends DiffXAlgorithmBase {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private transient Matrix matrix;
|
||||
|
||||
private transient ElementState estate = new ElementState();
|
||||
|
||||
public DiffXFitWesyma(EventSequence seq0, EventSequence seq1) {
|
||||
super(seq0, seq1);
|
||||
this.matrix = setupMatrix(seq0, seq1);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
this.length = 0;
|
||||
if (this.length < 0) {
|
||||
this.matrix.setup(this.length1 + 1, this.length2 + 1);
|
||||
for (int i = this.length1; i >= 0; i--) {
|
||||
for (int j = this.length2; j >= 0; j--) {
|
||||
if (i >= this.length1 || j >= this.length2) {
|
||||
this.matrix.set(i, j, 0);
|
||||
} else if (this.sequence1.getEvent(i).equals(this.sequence2.getEvent(j))) {
|
||||
this.matrix.incrementPathBy(i, j, maxWeight(this.sequence1.getEvent(i), this.sequence2.getEvent(j)));
|
||||
} else {
|
||||
this.matrix.incrementByMaxPath(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.length = this.matrix.get(0, 0);
|
||||
}
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public void process(DiffXFormatter formatter) throws IOException {
|
||||
processEmpty(formatter);
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
return;
|
||||
length();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
while (i < this.length1 && j < this.length2) {
|
||||
e1 = this.sequence1.getEvent(i);
|
||||
e2 = this.sequence2.getEvent(j);
|
||||
if (e1.equals(e2)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.matrix.isGreaterX(i, j)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (this.matrix.isGreaterY(i, j)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.matrix.isSameXY(i, j)) {
|
||||
boolean priorityInsert = true;
|
||||
if (this.estate.matchCurrent(e1))
|
||||
priorityInsert = true;
|
||||
if (this.estate.matchCurrent(e2))
|
||||
priorityInsert = false;
|
||||
if (e1 instanceof com.topologi.diffx.event.AttributeEvent && !(e2 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
priorityInsert = true;
|
||||
} else if (e2 instanceof com.topologi.diffx.event.AttributeEvent && !(e1 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
priorityInsert = false;
|
||||
}
|
||||
if (priorityInsert) {
|
||||
this.estate.insert(e1);
|
||||
formatter.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
this.estate.delete(e1);
|
||||
formatter.delete(e2);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
while (i < this.length1) {
|
||||
this.estate.insert(this.sequence1.getEvent(i));
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
i++;
|
||||
}
|
||||
while (j < this.length2) {
|
||||
this.estate.delete(this.sequence2.getEvent(j));
|
||||
formatter.delete(this.sequence2.getEvent(j));
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
private void processEmpty(DiffXFormatter formatter) throws IOException {
|
||||
if (this.length1 == 0)
|
||||
for (int i = 0; i < this.length2; i++)
|
||||
formatter.delete(this.sequence2.getEvent(i));
|
||||
if (this.length2 == 0)
|
||||
for (int i = 0; i < this.length1; i++)
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
}
|
||||
|
||||
private static Matrix setupMatrix(EventSequence s1, EventSequence s2) {
|
||||
int max = 0;
|
||||
for (int j = 0; j < s1.size(); j++)
|
||||
max += s1.getEvent(j).getWeight();
|
||||
for (int i = 0; i < s2.size(); i++)
|
||||
max += s2.getEvent(i).getWeight();
|
||||
if (max > 32767)
|
||||
return new MatrixInt();
|
||||
return new MatrixShort();
|
||||
}
|
||||
|
||||
private int maxWeight(DiffXEvent e1, DiffXEvent e2) {
|
||||
return (e1.getWeight() > e2.getWeight()) ? e1.getWeight() : e2.getWeight();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.format.ShortStringFormatter;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class DiffXFitopsy extends DiffXAlgorithmBase {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private transient Matrix matrix;
|
||||
|
||||
private transient ElementState estate = new ElementState();
|
||||
|
||||
public DiffXFitopsy(EventSequence seq0, EventSequence seq1) {
|
||||
super(seq0, seq1);
|
||||
this.matrix = setupMatrix(seq0, seq1);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
this.length = 0;
|
||||
if (this.length < 0) {
|
||||
this.matrix.setup(this.length1 + 1, this.length2 + 1);
|
||||
for (int i = this.length1; i >= 0; i--) {
|
||||
for (int j = this.length2; j >= 0; j--) {
|
||||
if (i >= this.length1 || j >= this.length2) {
|
||||
this.matrix.set(i, j, 0);
|
||||
} else if (this.sequence1.getEvent(i).equals(this.sequence2.getEvent(j))) {
|
||||
this.matrix.incrementPathBy(i, j, 1);
|
||||
} else {
|
||||
this.matrix.incrementByMaxPath(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.length = this.matrix.get(0, 0);
|
||||
}
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public void process(DiffXFormatter formatter) throws IOException {
|
||||
processEmpty(formatter);
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
return;
|
||||
length();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
while (i < this.length1 && j < this.length2) {
|
||||
e1 = this.sequence1.getEvent(i);
|
||||
e2 = this.sequence2.getEvent(j);
|
||||
if (this.matrix.isGreaterX(i, j)) {
|
||||
if (this.estate.okInsert(e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (e1.equals(e2) && this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isGreaterY(i, j)) {
|
||||
if (this.estate.okDelete(e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (e1.equals(e2) && this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okInsert(e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isSameXY(i, j)) {
|
||||
if (e1.equals(e2) && this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okInsert(e1) && (!(e2 instanceof com.topologi.diffx.event.AttributeEvent) || e1 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
this.estate.insert(e1);
|
||||
formatter.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2) && (!(e1 instanceof com.topologi.diffx.event.AttributeEvent) || e2 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while (i < this.length1) {
|
||||
this.estate.insert(this.sequence1.getEvent(i));
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
i++;
|
||||
}
|
||||
while (j < this.length2) {
|
||||
this.estate.delete(this.sequence2.getEvent(j));
|
||||
formatter.delete(this.sequence2.getEvent(j));
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
private void processEmpty(DiffXFormatter formatter) throws IOException {
|
||||
if (this.length1 == 0)
|
||||
for (int i = 0; i < this.length2; i++)
|
||||
formatter.delete(this.sequence2.getEvent(i));
|
||||
if (this.length2 == 0)
|
||||
for (int i = 0; i < this.length1; i++)
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
}
|
||||
|
||||
private static Matrix setupMatrix(EventSequence s1, EventSequence s2) {
|
||||
int max = 0;
|
||||
for (int j = 0; j < s1.size(); j++)
|
||||
max += s1.getEvent(j).getWeight();
|
||||
for (int i = 0; i < s2.size(); i++)
|
||||
max += s2.getEvent(i).getWeight();
|
||||
if (max > 32767)
|
||||
return new MatrixInt();
|
||||
return new MatrixShort();
|
||||
}
|
||||
|
||||
private void printLost(int i, int j) {
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
System.err.println("(!) Ambiguous choice in (" + i + "," + j + ")");
|
||||
System.err.println(" ? +" + ShortStringFormatter.toShortString(e1));
|
||||
System.err.println(" ? -" + ShortStringFormatter.toShortString(e2));
|
||||
System.err.println(" current=" + ShortStringFormatter.toShortString(this.estate.current()));
|
||||
System.err.println(" value in X+1=" + this.matrix.get(i + 1, j));
|
||||
System.err.println(" value in Y+1=" + this.matrix.get(i, j + 1));
|
||||
System.err.println(" equals=" + e1.equals(e2));
|
||||
System.err.println(" greaterX=" + this.matrix.isGreaterX(i, j));
|
||||
System.err.println(" greaterY=" + this.matrix.isGreaterY(i, j));
|
||||
System.err.println(" sameXY=" + this.matrix.isSameXY(i, j));
|
||||
System.err.println(" okFormat1=" + this.estate.okFormat(e1));
|
||||
System.err.println(" okFormat2=" + this.estate.okFormat(e2));
|
||||
System.err.println(" okInsert=" + this.estate.okInsert(e1));
|
||||
System.err.println(" okDelete=" + this.estate.okDelete(e2));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.format.ShortStringFormatter;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class DiffXFitsy extends DiffXAlgorithmBase {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final boolean PROFILE = false;
|
||||
|
||||
private transient Matrix matrix;
|
||||
|
||||
private transient ElementState estate = new ElementState();
|
||||
|
||||
public DiffXFitsy(EventSequence seq0, EventSequence seq1) {
|
||||
super(seq0, seq1);
|
||||
this.matrix = setupMatrix(seq0, seq1);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
this.length = 0;
|
||||
if (this.length < 0) {
|
||||
long t0 = System.currentTimeMillis();
|
||||
this.matrix.setup(this.length1 + 1, this.length2 + 1);
|
||||
long t1 = System.currentTimeMillis();
|
||||
for (int i = this.length1; i >= 0; i--) {
|
||||
for (int j = this.length2; j >= 0; j--) {
|
||||
if (i >= this.length1 || j >= this.length2) {
|
||||
this.matrix.set(i, j, 0);
|
||||
} else if (this.sequence1.getEvent(i).equals(this.sequence2.getEvent(j))) {
|
||||
this.matrix.incrementPathBy(i, j, maxWeight(this.sequence1.getEvent(i), this.sequence2.getEvent(j)));
|
||||
} else {
|
||||
this.matrix.incrementByMaxPath(i, j);
|
||||
}
|
||||
}
|
||||
if (i % (this.length1 / 50) == 0)
|
||||
System.err.println((i * 100 / this.length1) + "% at " + (t1 - System.currentTimeMillis()) + "ms");
|
||||
}
|
||||
this.length = this.matrix.get(0, 0);
|
||||
System.err.println((System.currentTimeMillis() - t1) + " ms to populate");
|
||||
}
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public void process(DiffXFormatter formatter) throws IOException {
|
||||
processEmpty(formatter);
|
||||
System.err.println("Start processing");
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
return;
|
||||
length();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
while (i < this.length1 && j < this.length2) {
|
||||
e1 = this.sequence1.getEvent(i);
|
||||
e2 = this.sequence2.getEvent(j);
|
||||
if (e1.equals(e2)) {
|
||||
if (this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okInsert(e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isGreaterX(i, j)) {
|
||||
if (this.estate.okInsert(e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isGreaterY(i, j)) {
|
||||
if (this.estate.okDelete(e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okInsert(e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isSameXY(i, j)) {
|
||||
if (this.estate.okInsert(e1) && (!(e2 instanceof com.topologi.diffx.event.AttributeEvent) || e1 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
this.estate.insert(e1);
|
||||
formatter.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2) && (!(e1 instanceof com.topologi.diffx.event.AttributeEvent) || e2 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while (i < this.length1) {
|
||||
this.estate.insert(this.sequence1.getEvent(i));
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
i++;
|
||||
}
|
||||
while (j < this.length2) {
|
||||
this.estate.delete(this.sequence2.getEvent(j));
|
||||
formatter.delete(this.sequence2.getEvent(j));
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
private void processEmpty(DiffXFormatter formatter) throws IOException {
|
||||
if (this.length1 == 0)
|
||||
for (int i = 0; i < this.length2; i++)
|
||||
formatter.delete(this.sequence2.getEvent(i));
|
||||
if (this.length2 == 0)
|
||||
for (int i = 0; i < this.length1; i++)
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
}
|
||||
|
||||
private static Matrix setupMatrix(EventSequence s1, EventSequence s2) {
|
||||
int max = 0;
|
||||
for (int j = 0; j < s1.size(); j++)
|
||||
max += s1.getEvent(j).getWeight();
|
||||
for (int i = 0; i < s2.size(); i++)
|
||||
max += s2.getEvent(i).getWeight();
|
||||
if (max > 32767)
|
||||
return new MatrixInt();
|
||||
return new MatrixShort();
|
||||
}
|
||||
|
||||
private int maxWeight(DiffXEvent e1, DiffXEvent e2) {
|
||||
return (e1.getWeight() > e2.getWeight()) ? e1.getWeight() : e2.getWeight();
|
||||
}
|
||||
|
||||
private void printLost(int i, int j) {
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
System.err.println("(!) Ambiguous choice in (" + i + "," + j + ")");
|
||||
System.err.println(" ? +" + ShortStringFormatter.toShortString(e1));
|
||||
System.err.println(" ? -" + ShortStringFormatter.toShortString(e2));
|
||||
System.err.println(" current=" + ShortStringFormatter.toShortString(this.estate.current()));
|
||||
System.err.println(" value in X+1=" + this.matrix.get(i + 1, j));
|
||||
System.err.println(" value in Y+1=" + this.matrix.get(i, j + 1));
|
||||
System.err.println(" equals=" + e1.equals(e2));
|
||||
System.err.println(" greaterX=" + this.matrix.isGreaterX(i, j));
|
||||
System.err.println(" greaterY=" + this.matrix.isGreaterY(i, j));
|
||||
System.err.println(" sameXY=" + this.matrix.isSameXY(i, j));
|
||||
System.err.println(" okFormat1=" + this.estate.okFormat(e1));
|
||||
System.err.println(" okFormat2=" + this.estate.okFormat(e2));
|
||||
System.err.println(" okInsert=" + this.estate.okInsert(e1));
|
||||
System.err.println(" okDelete=" + this.estate.okDelete(e2));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class DiffXKumarRangan extends DiffXAlgorithmBase {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private int[] R1;
|
||||
|
||||
private int[] R2;
|
||||
|
||||
private int[] LL;
|
||||
|
||||
private int[] LL1;
|
||||
|
||||
private int[] LL2;
|
||||
|
||||
private int R;
|
||||
|
||||
private int S;
|
||||
|
||||
private int iSeq2 = 0;
|
||||
|
||||
private int length = -1;
|
||||
|
||||
private DiffXFormatter df = null;
|
||||
|
||||
public DiffXKumarRangan(EventSequence seq0, EventSequence seq1) {
|
||||
super(seq0, seq1);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (this.length < 0)
|
||||
this.length = calculateLength();
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public void process(DiffXFormatter formatter) throws IOException {
|
||||
this.length = calculateLength();
|
||||
this.df = formatter;
|
||||
generateLCS(0, this.length1 - 1, 0, this.length2 - 1, this.length1, this.length2, this.length);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
this.R1 = new int[this.length2 + 1];
|
||||
this.R2 = new int[this.length2 + 1];
|
||||
this.LL = new int[this.length2 + 1];
|
||||
this.LL1 = new int[this.length2 + 1];
|
||||
this.LL2 = new int[this.length2 + 1];
|
||||
this.iSeq2 = 0;
|
||||
}
|
||||
|
||||
private int calculateLength() {
|
||||
init();
|
||||
this.R = 0;
|
||||
this.S = this.length1 + 1;
|
||||
while (this.S > this.R) {
|
||||
this.S--;
|
||||
fillOne(0, this.length1 - 1, 0, this.length2 - 1, this.length1, this.length2, 1);
|
||||
copyUpTo(this.R2, this.R1, this.R);
|
||||
}
|
||||
return this.S;
|
||||
}
|
||||
|
||||
private void fillOne(int start1, int end1, int start2, int end2, int m, int n, int sign) {
|
||||
int j = 1;
|
||||
int i = this.S;
|
||||
boolean over = false;
|
||||
this.R2[0] = n + 1;
|
||||
int lower2 = 0;
|
||||
int position2 = 0;
|
||||
int temp = 0;
|
||||
while (((i > 0) ? true : false) & (!over ? true : false)) {
|
||||
if (j > this.R) {
|
||||
lower2 = 0;
|
||||
} else {
|
||||
lower2 = this.R1[j];
|
||||
}
|
||||
position2 = this.R2[j - 1] - 1;
|
||||
while (position2 > lower2 && !this.sequence1.getEvent((i - 1) * sign + start1).equals(this.sequence2.getEvent((position2 - 1) * sign + start2)))
|
||||
position2--;
|
||||
temp = Math.max(position2, lower2);
|
||||
if (temp == 0) {
|
||||
over = true;
|
||||
continue;
|
||||
}
|
||||
this.R2[j] = temp;
|
||||
i--;
|
||||
j++;
|
||||
}
|
||||
this.R = j - 1;
|
||||
}
|
||||
|
||||
private int[] calMid(int start1, int end1, int start2, int end2, int m, int n, int sign, int waste) {
|
||||
this.LL = new int[n + 1];
|
||||
this.R = 0;
|
||||
for (this.S = m; this.S >= m - waste; this.S--) {
|
||||
fillOne(start1, end1, start2, end2, m, n, sign);
|
||||
copyUpTo(this.R2, this.R1, this.R);
|
||||
}
|
||||
copyUpTo(this.R1, this.LL, this.R);
|
||||
return this.LL;
|
||||
}
|
||||
|
||||
private void generateLCS(int start1, int end1, int start2, int end2, int m, int n, int lcs) throws IOException {
|
||||
if (m - lcs < 2) {
|
||||
getLCSMinimumWaste(start1, end1, start2, end2, m, n, lcs);
|
||||
} else {
|
||||
getLCSMoreWaste(start1, end1, start2, end2, m, n, lcs);
|
||||
}
|
||||
}
|
||||
|
||||
private void getLCSMinimumWaste(int start1, int end1, int start2, int end2, int m, int n, int lcs) throws IOException {
|
||||
int waste = m - lcs;
|
||||
this.LL = calMid(start1, end1, start2, end2, m, n, 1, waste);
|
||||
int i = 0;
|
||||
while (i < lcs && this.sequence1.getEvent(i + start1).equals(this.sequence2.getEvent(this.LL[lcs - i] - 1 + start2))) {
|
||||
this.df.format(this.sequence1.getEvent(i + start1));
|
||||
this.iSeq2++;
|
||||
i++;
|
||||
if (i < lcs)
|
||||
writeDeleted(this.LL[lcs - i] - 1 + start2);
|
||||
}
|
||||
if (i < m)
|
||||
this.df.insert(this.sequence1.getEvent(i + start1));
|
||||
if (i < lcs)
|
||||
writeDeleted(this.LL[lcs - i] - 1 + start2);
|
||||
i++;
|
||||
while (i < m) {
|
||||
this.df.format(this.sequence1.getEvent(i + start1));
|
||||
this.iSeq2++;
|
||||
writeDeleted(this.LL[m - i] - 1 + start2);
|
||||
i++;
|
||||
}
|
||||
writeDeleted(this.LL[0] - 1 + start2);
|
||||
}
|
||||
|
||||
private void getLCSMoreWaste(int start1, int end1, int start2, int end2, int m, int n, int lcs) throws IOException {
|
||||
int waste1 = (int)Math.ceil((double)((float)(m - lcs) / 2.0F));
|
||||
this.LL1 = calMid(end1, start1, end2, start2, m, n, -1, waste1);
|
||||
int r1 = this.R;
|
||||
for (int j = 0; j <= r1; j++)
|
||||
this.LL1[j] = n + 1 - this.LL1[j];
|
||||
int waste2 = (int)Math.floor((double)((float)(m - lcs) / 2.0F));
|
||||
this.LL2 = calMid(start1, end1, start2, end2, m, n, 1, waste2);
|
||||
int r2 = this.R;
|
||||
int k = Math.max(r1, r2);
|
||||
while (k > 0 && (
|
||||
k > r1 || lcs - k > r2 || this.LL1[k] >= this.LL2[lcs - k]))
|
||||
k--;
|
||||
int u = k + waste1;
|
||||
int v = this.LL1[k];
|
||||
generateLCS(start1, start1 + u - 1, start2, start2 + v - 1, u - 1 + 1, v - 1 + 1, u - waste1);
|
||||
generateLCS(start1 + u, end1, start2 + v, end2, end1 - start1 + 1 - u, end2 - start2 + 1 - v, m - u - waste2);
|
||||
}
|
||||
|
||||
private void writeDeleted(int jSeq2) throws IOException {
|
||||
while (jSeq2 > this.iSeq2)
|
||||
this.df.delete(this.sequence2.getEvent(this.iSeq2++));
|
||||
}
|
||||
|
||||
private void printState(int f) {
|
||||
if ((f & 0x1) == 1)
|
||||
System.err.println(" R=" + this.R);
|
||||
if ((f & 0x10) == 16)
|
||||
System.err.println(" S=" + this.S);
|
||||
if ((f & 0x11) > 0)
|
||||
System.err.println();
|
||||
if ((f & 0x100) == 256) {
|
||||
System.err.print(" R1={");
|
||||
for (int element : this.R1)
|
||||
System.err.print(" " + element);
|
||||
System.err.println(" }");
|
||||
}
|
||||
if ((f & 0x1000) == 4096) {
|
||||
System.err.print(" R2={");
|
||||
for (int element : this.R2)
|
||||
System.err.print(" " + element);
|
||||
System.err.println(" }");
|
||||
}
|
||||
if ((f & 0x10000) == 65536) {
|
||||
System.err.print(" LL={");
|
||||
for (int element : this.LL)
|
||||
System.err.print(" " + element);
|
||||
System.err.println(" }");
|
||||
}
|
||||
if ((f & 0x100000) == 1048576) {
|
||||
System.err.print(" LL1={");
|
||||
for (int element : this.LL1)
|
||||
System.err.print(" " + element);
|
||||
System.err.println(" }");
|
||||
}
|
||||
if ((f & 0x1000000) == 16777216) {
|
||||
System.err.print(" LL2={");
|
||||
for (int element : this.LL2)
|
||||
System.err.print(" " + element);
|
||||
System.err.println(" }");
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyUpTo(int[] a, int[] b, int len) {
|
||||
for (int i = 0; i <= len; i++)
|
||||
b[i] = a[i];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
|
||||
public final class ElementState {
|
||||
private transient OpenElementEvent[] openElements;
|
||||
|
||||
private transient char[] openChanges;
|
||||
|
||||
private transient int size;
|
||||
|
||||
public ElementState(int initialCapacity) throws IllegalArgumentException {
|
||||
if (initialCapacity < 0)
|
||||
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
|
||||
this.openElements = new OpenElementEvent[initialCapacity];
|
||||
this.openChanges = new char[initialCapacity];
|
||||
}
|
||||
|
||||
public ElementState() {
|
||||
this(12);
|
||||
}
|
||||
|
||||
public void ensureCapacity(int minCapacity) {
|
||||
int oldCapacity = this.openElements.length;
|
||||
if (minCapacity > oldCapacity) {
|
||||
OpenElementEvent[] oldElements = this.openElements;
|
||||
char[] oldChanges = this.openChanges;
|
||||
int newCapacity = oldCapacity * 3 / 2 + 1;
|
||||
if (newCapacity < minCapacity)
|
||||
newCapacity = minCapacity;
|
||||
this.openElements = new OpenElementEvent[newCapacity];
|
||||
this.openChanges = new char[newCapacity];
|
||||
System.arraycopy(oldElements, 0, this.openElements, 0, this.size);
|
||||
System.arraycopy(oldChanges, 0, this.openChanges, 0, this.size);
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return (this.size == 0);
|
||||
}
|
||||
|
||||
public boolean contains(OpenElementEvent element) {
|
||||
return (indexOf(element) >= 0);
|
||||
}
|
||||
|
||||
public int indexOf(OpenElementEvent element) {
|
||||
if (element == null) {
|
||||
for (int i = 0; i < this.size; i++) {
|
||||
if (this.openElements[i] == null)
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < this.size; i++) {
|
||||
if (element.equals((DiffXEvent)this.openElements[i]))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int lastIndexOf(OpenElementEvent element) {
|
||||
if (element == null) {
|
||||
for (int i = this.size - 1; i >= 0; i--) {
|
||||
if (this.openElements[i] == null)
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
for (int i = this.size - 1; i >= 0; i--) {
|
||||
if (element.equals((DiffXEvent)this.openElements[i]))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public OpenElementEvent current() {
|
||||
if (!isEmpty())
|
||||
return this.openElements[this.size - 1];
|
||||
return null;
|
||||
}
|
||||
|
||||
public char currentChange() {
|
||||
if (!isEmpty())
|
||||
return this.openChanges[this.size - 1];
|
||||
return ' ';
|
||||
}
|
||||
|
||||
public boolean matchCurrent(DiffXEvent e) {
|
||||
if (isEmpty())
|
||||
return false;
|
||||
if (!(e instanceof CloseElementEvent))
|
||||
return false;
|
||||
return ((CloseElementEvent)e).match(current());
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) {
|
||||
if (e instanceof OpenElementEvent) {
|
||||
push((OpenElementEvent)e, '+');
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) {
|
||||
if (e instanceof OpenElementEvent) {
|
||||
push((OpenElementEvent)e, '=');
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) {
|
||||
if (e instanceof OpenElementEvent) {
|
||||
push((OpenElementEvent)e, '-');
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean okFormat(DiffXEvent e) {
|
||||
if (!(e instanceof CloseElementEvent))
|
||||
return true;
|
||||
if (isEmpty())
|
||||
return false;
|
||||
return (((CloseElementEvent)e).match(current()) && this.openChanges[this.size - 1] == '=');
|
||||
}
|
||||
|
||||
public boolean okInsert(DiffXEvent e) {
|
||||
if (!(e instanceof CloseElementEvent))
|
||||
return true;
|
||||
if (isEmpty())
|
||||
return false;
|
||||
return (((CloseElementEvent)e).match(current()) && this.openChanges[this.size - 1] == '+');
|
||||
}
|
||||
|
||||
public boolean okDelete(DiffXEvent e) {
|
||||
if (!(e instanceof CloseElementEvent))
|
||||
return true;
|
||||
if (isEmpty())
|
||||
return false;
|
||||
return (((CloseElementEvent)e).match(current()) && this.openChanges[this.size - 1] == '-');
|
||||
}
|
||||
|
||||
public boolean hasPriorityOver(DiffXEvent e1, DiffXEvent e2) {
|
||||
if (e1 instanceof com.topologi.diffx.event.AttributeEvent && !(e2 instanceof com.topologi.diffx.event.AttributeEvent) && !isEmpty())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void push(OpenElementEvent e, char c) {
|
||||
ensureCapacity(this.size + 1);
|
||||
this.openElements[this.size] = e;
|
||||
this.openChanges[this.size] = c;
|
||||
this.size++;
|
||||
}
|
||||
|
||||
public OpenElementEvent pop() {
|
||||
if (this.size > 0) {
|
||||
this.size--;
|
||||
return this.openElements[this.size];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public OpenElementEvent get(int index) throws IndexOutOfBoundsException {
|
||||
checkRange(index);
|
||||
return this.openElements[index];
|
||||
}
|
||||
|
||||
public OpenElementEvent remove(int index) throws IndexOutOfBoundsException {
|
||||
checkRange(index);
|
||||
OpenElementEvent oldValue = this.openElements[index];
|
||||
int numMoved = this.size - index - 1;
|
||||
if (numMoved > 0)
|
||||
System.arraycopy(this.openElements, index + 1, this.openElements, index, numMoved);
|
||||
this.openElements[--this.size] = null;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
for (int i = 0; i < this.size; i++)
|
||||
this.openElements[i] = null;
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
private void checkRange(int index) throws IndexOutOfBoundsException {
|
||||
if (index >= this.size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.size);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.DiffXException;
|
||||
|
||||
public final class FactoryException extends DiffXException {
|
||||
private static final long serialVersionUID = -4029990831933233646L;
|
||||
|
||||
public FactoryException(Exception ex) {
|
||||
super(ex);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import com.topologi.diffx.format.ShortStringFormatter;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class GuanoAlgorithm implements DiffXAlgorithm {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final EventSequence sequence1;
|
||||
|
||||
private final EventSequence sequence2;
|
||||
|
||||
private final int length1;
|
||||
|
||||
private final int length2;
|
||||
|
||||
private transient Matrix matrix;
|
||||
|
||||
private transient ElementState estate = new ElementState();
|
||||
|
||||
private transient int length = -1;
|
||||
|
||||
public GuanoAlgorithm(EventSequence seq0, EventSequence seq1) {
|
||||
this.sequence1 = seq0;
|
||||
this.sequence2 = seq1;
|
||||
this.length1 = seq0.size();
|
||||
this.length2 = seq1.size();
|
||||
this.matrix = setupMatrix(seq0, seq1);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
this.length = 0;
|
||||
if (this.length < 0) {
|
||||
this.matrix.setup(this.length1 + 1, this.length2 + 1);
|
||||
for (int i = this.length1; i >= 0; i--) {
|
||||
for (int j = this.length2; j >= 0; j--) {
|
||||
if (i >= this.length1 || j >= this.length2) {
|
||||
this.matrix.set(i, j, 0);
|
||||
} else if (this.sequence1.getEvent(i).equals(this.sequence2.getEvent(j))) {
|
||||
this.matrix.incrementPathBy(i, j, 1);
|
||||
} else {
|
||||
this.matrix.incrementByMaxPath(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.length = this.matrix.get(0, 0);
|
||||
}
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public void process(DiffXFormatter formatter) throws IOException {
|
||||
processEmpty(formatter);
|
||||
if (this.length1 == 0 || this.length2 == 0)
|
||||
return;
|
||||
length();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
while (i < this.length1 && j < this.length2) {
|
||||
e1 = this.sequence1.getEvent(i);
|
||||
e2 = this.sequence2.getEvent(j);
|
||||
if (this.matrix.isGreaterX(i, j)) {
|
||||
if (this.estate.okInsert(e1) && !this.estate.hasPriorityOver(e2, e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (e1.equals(e2) && this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isGreaterY(i, j)) {
|
||||
if (this.estate.okDelete(e2) && !this.estate.hasPriorityOver(e1, e2)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (e1.equals(e2) && this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okInsert(e1)) {
|
||||
formatter.insert(e1);
|
||||
this.estate.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.matrix.isSameXY(i, j)) {
|
||||
if (e1.equals(e2) && this.estate.okFormat(e1)) {
|
||||
formatter.format(e1);
|
||||
this.estate.format(e1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okInsert(e1) && (!(e2 instanceof com.topologi.diffx.event.AttributeEvent) || e1 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
this.estate.insert(e1);
|
||||
formatter.insert(e1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (this.estate.okDelete(e2) && (!(e1 instanceof com.topologi.diffx.event.AttributeEvent) || e2 instanceof com.topologi.diffx.event.AttributeEvent)) {
|
||||
formatter.delete(e2);
|
||||
this.estate.delete(e2);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while (i < this.length1) {
|
||||
this.estate.insert(this.sequence1.getEvent(i));
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
i++;
|
||||
}
|
||||
while (j < this.length2) {
|
||||
this.estate.delete(this.sequence2.getEvent(j));
|
||||
formatter.delete(this.sequence2.getEvent(j));
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
public final EventSequence getFirstSequence() {
|
||||
return this.sequence1;
|
||||
}
|
||||
|
||||
public final EventSequence getSecondSequence() {
|
||||
return this.sequence2;
|
||||
}
|
||||
|
||||
private void processEmpty(DiffXFormatter formatter) throws IOException {
|
||||
if (this.length1 == 0)
|
||||
for (int i = 0; i < this.length2; i++)
|
||||
formatter.delete(this.sequence2.getEvent(i));
|
||||
if (this.length2 == 0)
|
||||
for (int i = 0; i < this.length1; i++)
|
||||
formatter.insert(this.sequence1.getEvent(i));
|
||||
}
|
||||
|
||||
private static Matrix setupMatrix(EventSequence s1, EventSequence s2) {
|
||||
int max = 0;
|
||||
for (int j = 0; j < s1.size(); j++)
|
||||
max += s1.getEvent(j).getWeight();
|
||||
for (int i = 0; i < s2.size(); i++)
|
||||
max += s2.getEvent(i).getWeight();
|
||||
if (max > 32767)
|
||||
return new MatrixInt();
|
||||
return new MatrixShort();
|
||||
}
|
||||
|
||||
private void printLost(int i, int j) {
|
||||
DiffXEvent e1 = this.sequence1.getEvent(i);
|
||||
DiffXEvent e2 = this.sequence2.getEvent(j);
|
||||
System.err.println("(!) Ambiguous choice in (" + i + "," + j + ")");
|
||||
System.err.println(" ? +" + ShortStringFormatter.toShortString(e1));
|
||||
System.err.println(" ? -" + ShortStringFormatter.toShortString(e2));
|
||||
System.err.println(" current=" + ShortStringFormatter.toShortString(this.estate.current()));
|
||||
System.err.println(" value in X+1=" + this.matrix.get(i + 1, j));
|
||||
System.err.println(" value in Y+1=" + this.matrix.get(i, j + 1));
|
||||
System.err.println(" equals=" + e1.equals(e2));
|
||||
System.err.println(" greaterX=" + this.matrix.isGreaterX(i, j));
|
||||
System.err.println(" greaterY=" + this.matrix.isGreaterY(i, j));
|
||||
System.err.println(" sameXY=" + this.matrix.isSameXY(i, j));
|
||||
System.err.println(" okFormat1=" + this.estate.okFormat(e1));
|
||||
System.err.println(" okFormat2=" + this.estate.okFormat(e2));
|
||||
System.err.println(" okInsert=" + this.estate.okInsert(e1));
|
||||
System.err.println(" okDelete=" + this.estate.okDelete(e2));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
public interface Matrix {
|
||||
void setup(int paramInt1, int paramInt2);
|
||||
|
||||
void set(int paramInt1, int paramInt2, int paramInt3);
|
||||
|
||||
int get(int paramInt1, int paramInt2);
|
||||
|
||||
void incrementPathBy(int paramInt1, int paramInt2, int paramInt3);
|
||||
|
||||
void incrementByMaxPath(int paramInt1, int paramInt2);
|
||||
|
||||
boolean isGreaterX(int paramInt1, int paramInt2);
|
||||
|
||||
boolean isGreaterY(int paramInt1, int paramInt2);
|
||||
|
||||
boolean isSameXY(int paramInt1, int paramInt2);
|
||||
|
||||
void release();
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
public final class MatrixInt implements Matrix {
|
||||
private int[][] matrix;
|
||||
|
||||
public void setup(int width, int height) {
|
||||
this.matrix = new int[width][height];
|
||||
}
|
||||
|
||||
public void set(int i, int j, int x) {
|
||||
this.matrix[i][j] = x;
|
||||
}
|
||||
|
||||
public int get(int i, int j) {
|
||||
return this.matrix[i][j];
|
||||
}
|
||||
|
||||
public void incrementPathBy(int i, int j, int n) {
|
||||
this.matrix[i][j] = this.matrix[i + 1][j + 1] + n;
|
||||
}
|
||||
|
||||
public void incrementByMaxPath(int i, int j) {
|
||||
this.matrix[i][j] = Math.max(this.matrix[i + 1][j], this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public boolean isGreaterX(int i, int j) {
|
||||
return (this.matrix[i + 1][j] > this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public boolean isGreaterY(int i, int j) {
|
||||
return (this.matrix[i + 1][j] < this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public boolean isSameXY(int i, int j) {
|
||||
return (this.matrix[i + 1][j] == this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
this.matrix = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.topologi.diffx.algorithm;
|
||||
|
||||
public final class MatrixShort implements Matrix {
|
||||
private short[][] matrix;
|
||||
|
||||
public void setup(int width, int height) {
|
||||
this.matrix = new short[width][height];
|
||||
}
|
||||
|
||||
public void set(int i, int j, int x) {
|
||||
this.matrix[i][j] = (short)x;
|
||||
}
|
||||
|
||||
public int get(int i, int j) {
|
||||
return this.matrix[i][j];
|
||||
}
|
||||
|
||||
public void incrementPathBy(int i, int j, int n) {
|
||||
this.matrix[i][j] = (short)(this.matrix[i + 1][j + 1] + n);
|
||||
}
|
||||
|
||||
public void incrementByMaxPath(int i, int j) {
|
||||
this.matrix[i][j] = max(this.matrix[i + 1][j], this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public boolean isGreaterX(int i, int j) {
|
||||
return (this.matrix[i + 1][j] > this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public boolean isGreaterY(int i, int j) {
|
||||
return (this.matrix[i + 1][j] < this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
public boolean isSameXY(int i, int j) {
|
||||
return (this.matrix[i + 1][j] == this.matrix[i][j + 1]);
|
||||
}
|
||||
|
||||
private static short max(short a, short b) {
|
||||
return (a >= b) ? a : b;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer out = new StringBuffer();
|
||||
for (int j = 0; j < (this.matrix[0]).length; j++) {
|
||||
for (short[] element : this.matrix)
|
||||
out.append(element[j] + "\t");
|
||||
out.append('\n');
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public void release() {
|
||||
this.matrix = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package com.topologi.diffx.config;
|
||||
|
||||
public final class DiffXConfig {
|
||||
private boolean isNamespaceAware = true;
|
||||
|
||||
private boolean reportPrefixDifferences = false;
|
||||
|
||||
private WhiteSpaceProcessing whitespace = WhiteSpaceProcessing.COMPARE;
|
||||
|
||||
private boolean preserveWhiteSpace = true;
|
||||
|
||||
private TextGranularity granularity = TextGranularity.WORD;
|
||||
|
||||
public DiffXConfig() {}
|
||||
|
||||
public DiffXConfig(TextGranularity granularity) {
|
||||
if (granularity == null)
|
||||
throw new NullPointerException("The granularity cannot be configured to be not be null.");
|
||||
this.granularity = granularity;
|
||||
}
|
||||
|
||||
public DiffXConfig(WhiteSpaceProcessing whitespace, TextGranularity granularity) {
|
||||
if (granularity == null)
|
||||
throw new NullPointerException("The granularity cannot be configured to be not be null.");
|
||||
if (whitespace == null)
|
||||
throw new NullPointerException("The whitespace processing cannot be configured to be not be null.");
|
||||
this.granularity = granularity;
|
||||
this.whitespace = whitespace;
|
||||
}
|
||||
|
||||
public void setGranularity(TextGranularity granularity) {
|
||||
if (granularity == null)
|
||||
throw new NullPointerException("The granularity cannot be configured to be not be null.");
|
||||
this.granularity = granularity;
|
||||
}
|
||||
|
||||
public void setWhiteSpaceProcessing(WhiteSpaceProcessing whitespace) {
|
||||
if (whitespace == null)
|
||||
throw new NullPointerException("The whitespace cannot be configured to be not be null.");
|
||||
this.whitespace = whitespace;
|
||||
}
|
||||
|
||||
public void setNamespaceAware(boolean aware) {
|
||||
this.isNamespaceAware = aware;
|
||||
if (!aware)
|
||||
this.reportPrefixDifferences = true;
|
||||
}
|
||||
|
||||
public void setReportPrefixDifferences(boolean report) {
|
||||
this.reportPrefixDifferences = report;
|
||||
if (!report)
|
||||
this.isNamespaceAware = true;
|
||||
}
|
||||
|
||||
public boolean isNamespaceAware() {
|
||||
return this.isNamespaceAware;
|
||||
}
|
||||
|
||||
public boolean isReportPrefixDifferences() {
|
||||
return this.reportPrefixDifferences;
|
||||
}
|
||||
|
||||
public TextGranularity getGranularity() {
|
||||
return this.granularity;
|
||||
}
|
||||
|
||||
public WhiteSpaceProcessing getWhiteSpaceProcessing() {
|
||||
return this.whitespace;
|
||||
}
|
||||
|
||||
public boolean isIgnoreWhiteSpace() {
|
||||
return (this.whitespace != WhiteSpaceProcessing.COMPARE);
|
||||
}
|
||||
|
||||
public boolean isPreserveWhiteSpace() {
|
||||
return this.preserveWhiteSpace;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setIgnoreWhiteSpace(boolean ignore) {
|
||||
if (!ignore) {
|
||||
this.whitespace = WhiteSpaceProcessing.COMPARE;
|
||||
} else {
|
||||
this.whitespace = this.preserveWhiteSpace ? WhiteSpaceProcessing.PRESERVE : WhiteSpaceProcessing.IGNORE;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setPreserveWhiteSpace(boolean preserve) {
|
||||
this.preserveWhiteSpace = preserve;
|
||||
if (this.whitespace != WhiteSpaceProcessing.COMPARE)
|
||||
this.whitespace = preserve ? WhiteSpaceProcessing.PRESERVE : WhiteSpaceProcessing.IGNORE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.topologi.diffx.config;
|
||||
|
||||
public enum TextGranularity {
|
||||
CHARACTER, WORD, TEXT;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.topologi.diffx.config;
|
||||
|
||||
public enum WhiteSpaceProcessing {
|
||||
IGNORE, PRESERVE, COMPARE;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.topologi.diffx.event;
|
||||
|
||||
public interface AttributeEvent extends DiffXEvent {
|
||||
String getName();
|
||||
|
||||
String getValue();
|
||||
|
||||
String getURI();
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.topologi.diffx.event;
|
||||
|
||||
public interface CloseElementEvent extends DiffXEvent {
|
||||
String getName();
|
||||
|
||||
String getURI();
|
||||
|
||||
OpenElementEvent getOpenElement();
|
||||
|
||||
boolean match(OpenElementEvent paramOpenElementEvent);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.topologi.diffx.event;
|
||||
|
||||
import com.topologi.diffx.xml.XMLFormattable;
|
||||
import com.topologi.diffx.xml.XMLWritable;
|
||||
|
||||
public interface DiffXEvent extends XMLWritable, XMLFormattable {
|
||||
boolean equals(DiffXEvent paramDiffXEvent);
|
||||
|
||||
int getWeight();
|
||||
|
||||
void setWeight(int paramInt);
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.topologi.diffx.event;
|
||||
|
||||
public interface OpenElementEvent extends DiffXEvent {
|
||||
String getName();
|
||||
|
||||
String getURI();
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.topologi.diffx.event;
|
||||
|
||||
public interface TextEvent extends DiffXEvent {
|
||||
String getCharacters();
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class AttributeEventImpl extends DiffXEventBase implements AttributeEvent {
|
||||
private final String name;
|
||||
|
||||
private final String value;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public AttributeEventImpl(String name, String value) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Attribute must have a name.");
|
||||
if (value == null)
|
||||
throw new NullPointerException("The attribute value cannot be null, use \"\".");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.hashCode = toHashCode(name, value);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
AttributeEventImpl bae = (AttributeEventImpl)e;
|
||||
return (bae.name.equals(this.name) && bae.value.equals(this.value));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "attribute: " + this.name + "=" + this.value;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.attribute(this.name, this.value);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append(' ');
|
||||
xml.append(this.name);
|
||||
xml.append("=\"");
|
||||
xml.append(ESC.toAttributeValue(this.value));
|
||||
xml.append('"');
|
||||
return xml;
|
||||
}
|
||||
|
||||
private static int toHashCode(String name, String value) {
|
||||
int hash = 23;
|
||||
hash = hash * 37 + ((name != null) ? name.hashCode() : 0);
|
||||
hash = hash * 37 + ((value != null) ? value.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class AttributeEventNSImpl extends DiffXEventBase implements AttributeEvent {
|
||||
private final String uri;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final String value;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public AttributeEventNSImpl(String name, String value) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Attribute must have a name.");
|
||||
if (value == null)
|
||||
throw new NullPointerException("The attribute value cannot be null, use \"\".");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.uri = null;
|
||||
this.hashCode = toHashCode(this.uri, name, value);
|
||||
}
|
||||
|
||||
public AttributeEventNSImpl(String uri, String name, String value) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Attribute must have a name.");
|
||||
if (value == null)
|
||||
throw new NullPointerException("The attribute value cannot be null, use \"\".");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.uri = uri;
|
||||
this.hashCode = toHashCode(uri, name, value);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
AttributeEventNSImpl ae = (AttributeEventNSImpl)e;
|
||||
if (!ae.name.equals(this.name))
|
||||
return false;
|
||||
if (!equals(ae.uri, this.uri))
|
||||
return false;
|
||||
if (!ae.value.equals(this.value))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "attribute: " + this.name + "=" + this.value + " [" + this.uri + "]";
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.attribute(this.uri, this.name, this.value);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append(' ');
|
||||
xml.append(this.name);
|
||||
xml.append("=\"");
|
||||
xml.append(ESC.toAttributeValue(this.value));
|
||||
xml.append('"');
|
||||
return xml;
|
||||
}
|
||||
|
||||
private static boolean equals(String uri1, String uri2) {
|
||||
if (uri1 == null && uri2 == null)
|
||||
return true;
|
||||
if (uri1 == null || uri2 == null)
|
||||
return false;
|
||||
return uri1.equals(uri2);
|
||||
}
|
||||
|
||||
private static int toHashCode(String uri, String name, String value) {
|
||||
int hash = 17;
|
||||
hash = hash * 31 + ((uri != null) ? uri.hashCode() : 0);
|
||||
hash = hash * 31 + ((name != null) ? name.hashCode() : 0);
|
||||
hash = hash * 31 + ((value != null) ? value.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class CharEvent extends DiffXEventBase {
|
||||
public final char c;
|
||||
|
||||
public CharEvent(char c) {
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return 79 + this.c;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
return (this.c == ((CharEvent)e).c);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "char: '" + this.c + '\'';
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.writeText(this.c);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
return xml.append(ESC.toElementText(new char[] { this.c }, 0, 1));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
public final class CharactersEvent extends CharactersEventBase {
|
||||
public CharactersEvent(CharSequence seq) throws NullPointerException {
|
||||
super(seq);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "characters: \"" + getCharacters() + '"';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class CharactersEventBase extends DiffXEventBase implements TextEvent {
|
||||
private final String characters;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public CharactersEventBase(CharSequence seq) throws NullPointerException {
|
||||
if (seq == null)
|
||||
throw new NullPointerException("The characters cannot be null, use \"\"");
|
||||
this.characters = seq.toString();
|
||||
this.hashCode = toHashCode(seq);
|
||||
}
|
||||
|
||||
public final int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public final boolean equals(DiffXEvent e) {
|
||||
if (this == e)
|
||||
return true;
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
CharactersEventBase ce = (CharactersEventBase)e;
|
||||
return ce.characters.equals(this.characters);
|
||||
}
|
||||
|
||||
public final String getCharacters() {
|
||||
return this.characters;
|
||||
}
|
||||
|
||||
public final void toXML(XMLWriter xml) throws IOException {
|
||||
xml.writeText(this.characters);
|
||||
}
|
||||
|
||||
public final StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append(ESC.toElementText(this.characters));
|
||||
return xml;
|
||||
}
|
||||
|
||||
private static int toHashCode(CharSequence s) {
|
||||
return 611 + ((s != null) ? s.hashCode() : 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class CloseElementEventImpl extends DiffXEventBase implements CloseElementEvent {
|
||||
private final OpenElementEvent open;
|
||||
|
||||
public CloseElementEventImpl(String name) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.open = new OpenElementEventImpl(name);
|
||||
}
|
||||
|
||||
public CloseElementEventImpl(OpenElementEvent event) throws NullPointerException {
|
||||
if (event == null)
|
||||
throw new NullPointerException("A close element must correspond to an open element.");
|
||||
this.open = event;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.open.getName();
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public OpenElementEvent getOpenElement() {
|
||||
return this.open;
|
||||
}
|
||||
|
||||
public boolean match(OpenElementEvent event) {
|
||||
if (event == null)
|
||||
return false;
|
||||
if (event == this.open)
|
||||
return true;
|
||||
return event.getName().equals(getName());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return 53 + this.open.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
CloseElementEventImpl ce = (CloseElementEventImpl)e;
|
||||
return ce.getName().equals(getName());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "closeElement: " + getName();
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.closeElement();
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append("</").append(getName()).append('>');
|
||||
return xml;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class CloseElementEventNSImpl extends DiffXEventBase implements CloseElementEvent {
|
||||
private final OpenElementEvent open;
|
||||
|
||||
public CloseElementEventNSImpl(String name) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.open = new OpenElementEventNSImpl(name);
|
||||
}
|
||||
|
||||
public CloseElementEventNSImpl(String uri, String name) throws NullPointerException {
|
||||
if (uri == null)
|
||||
throw new NullPointerException("The URI cannot be null, use \"\".");
|
||||
if (name == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.open = new OpenElementEventNSImpl(uri, name);
|
||||
}
|
||||
|
||||
public CloseElementEventNSImpl(OpenElementEvent event) throws NullPointerException {
|
||||
if (event == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.open = event;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.open.getName();
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return this.open.getURI();
|
||||
}
|
||||
|
||||
public OpenElementEvent getOpenElement() {
|
||||
return this.open;
|
||||
}
|
||||
|
||||
public boolean match(OpenElementEvent event) {
|
||||
if (event == null)
|
||||
return false;
|
||||
if (event == this.open)
|
||||
return true;
|
||||
return (event.getURI().equals(getURI()) && event.getName().equals(getName()));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return 89 + this.open.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
CloseElementEventNSImpl ce = (CloseElementEventNSImpl)e;
|
||||
return (ce.getURI().equals(getURI()) && ce.getName().equals(getName()));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "closeElement: " + getName() + " [" + getURI() + "]";
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.closeElement();
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append("</").append(getName()).append('>');
|
||||
return xml;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class CommentEvent extends DiffXEventBase implements DiffXEvent {
|
||||
private final String comment;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public CommentEvent(String comment) throws NullPointerException {
|
||||
this.comment = comment;
|
||||
this.hashCode = toHashcode(comment);
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return this.comment;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
CommentEvent ce = (CommentEvent)e;
|
||||
return ((ce.comment == null && this.comment == null) || ce.comment.equals(this.comment));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "comment: " + this.comment;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.writeComment(this.comment);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) {
|
||||
xml.append(this.comment);
|
||||
return xml;
|
||||
}
|
||||
|
||||
private int toHashcode(String comment) {
|
||||
return (comment != null) ? (703 + comment.hashCode()) : 703;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.esc.XMLEscape;
|
||||
import com.topologi.diffx.xml.esc.XMLEscapeUTF8;
|
||||
|
||||
abstract class DiffXEventBase implements DiffXEvent {
|
||||
static final XMLEscape ESC = XMLEscapeUTF8.UTF8_ESCAPE;
|
||||
|
||||
int weight = 1;
|
||||
|
||||
public abstract int hashCode();
|
||||
|
||||
public abstract boolean equals(DiffXEvent paramDiffXEvent);
|
||||
|
||||
public final boolean equals(Object o) {
|
||||
if (o == null)
|
||||
return false;
|
||||
if (!(o instanceof DiffXEvent))
|
||||
return false;
|
||||
return equals((DiffXEvent)o);
|
||||
}
|
||||
|
||||
public String toXML() {
|
||||
return toXML(new StringBuffer()).toString();
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return this.weight;
|
||||
}
|
||||
|
||||
public void setWeight(int weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
|
||||
public final class EventFactory {
|
||||
private boolean isNamespaceAware = true;
|
||||
|
||||
public EventFactory() {
|
||||
this.isNamespaceAware = true;
|
||||
}
|
||||
|
||||
public EventFactory(boolean isNamespaceAware) {
|
||||
this.isNamespaceAware = isNamespaceAware;
|
||||
}
|
||||
|
||||
public OpenElementEvent makeOpenElement(String uri, String name) {
|
||||
if (this.isNamespaceAware)
|
||||
return new OpenElementEventNSImpl(uri, name);
|
||||
return new OpenElementEventImpl(name);
|
||||
}
|
||||
|
||||
public OpenElementEvent makeOpenElement(String uri, String localName, String qName) {
|
||||
if (this.isNamespaceAware)
|
||||
return new OpenElementEventNSImpl(uri, localName);
|
||||
return new OpenElementEventImpl(qName);
|
||||
}
|
||||
|
||||
public CloseElementEvent makeCloseElement(OpenElementEvent open) {
|
||||
if (this.isNamespaceAware)
|
||||
return new CloseElementEventNSImpl(open);
|
||||
return new CloseElementEventImpl(open);
|
||||
}
|
||||
|
||||
public AttributeEvent makeAttribute(String uri, String name, String value) {
|
||||
if (this.isNamespaceAware)
|
||||
return new AttributeEventNSImpl("".equals(uri) ? null : uri, name, value);
|
||||
return new AttributeEventImpl(name, value);
|
||||
}
|
||||
|
||||
public AttributeEvent makeAttribute(String uri, String localName, String qName, String value) {
|
||||
if (this.isNamespaceAware)
|
||||
return new AttributeEventNSImpl("".equals(uri) ? null : uri, localName, value);
|
||||
return new AttributeEventImpl(qName, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class IgnorableSpaceEvent implements TextEvent {
|
||||
private final String characters;
|
||||
|
||||
public IgnorableSpaceEvent(CharSequence seq) throws NullPointerException {
|
||||
if (seq == null)
|
||||
throw new NullPointerException("The characters cannot be null, use \"\"");
|
||||
this.characters = seq.toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "ignorable-space";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return 71;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return (o.getClass() == getClass());
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (this == e)
|
||||
return true;
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getCharacters() {
|
||||
return this.characters;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.writeXML(this.characters);
|
||||
}
|
||||
|
||||
public String toXML() {
|
||||
return this.characters;
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append(this.characters);
|
||||
return xml;
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void setWeight(int weight) {}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class LineEvent extends DiffXEventBase implements TextEvent {
|
||||
private final CharSequence characters;
|
||||
|
||||
private final int lineNumber;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public LineEvent(CharSequence line, int lineNumber) throws NullPointerException {
|
||||
if (line == null)
|
||||
throw new NullPointerException("The line cannot be null, use \"\"");
|
||||
this.characters = line;
|
||||
this.lineNumber = lineNumber;
|
||||
this.hashCode = toHashCode(line);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "line:" + this.lineNumber + ": \"" + getCharacters() + '"';
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e == null)
|
||||
return false;
|
||||
if (this == e)
|
||||
return true;
|
||||
if (e.getClass() != LineEvent.class)
|
||||
return false;
|
||||
LineEvent ce = (LineEvent)e;
|
||||
return ce.characters.equals(this.characters);
|
||||
}
|
||||
|
||||
public String getCharacters() {
|
||||
return this.characters.toString();
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return this.lineNumber;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.writeXML(this.characters.toString());
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append(this.characters);
|
||||
return xml;
|
||||
}
|
||||
|
||||
private int toHashCode(CharSequence comment) {
|
||||
return (comment != null) ? (1711 + comment.hashCode()) : 1711;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class OpenElementEventImpl extends DiffXEventBase implements OpenElementEvent {
|
||||
private final String name;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public OpenElementEventImpl(String name) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.name = name;
|
||||
this.hashCode = toHashCode(name);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
OpenElementEventImpl oee = (OpenElementEventImpl)e;
|
||||
return oee.name.equals(this.name);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "openElement: " + this.name;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.openElement(this.name, false);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) {
|
||||
return xml.append('<').append(this.name).append('>');
|
||||
}
|
||||
|
||||
private static int toHashCode(String s) {
|
||||
return 451 + ((s != null) ? s.hashCode() : 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class OpenElementEventNSImpl extends DiffXEventBase implements DiffXEvent, OpenElementEvent {
|
||||
private final String uri;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public OpenElementEventNSImpl(String name) throws NullPointerException {
|
||||
if (name == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.uri = "";
|
||||
this.name = name;
|
||||
this.hashCode = toHashCode("", name);
|
||||
}
|
||||
|
||||
public OpenElementEventNSImpl(String uri, String name) throws NullPointerException {
|
||||
if (uri == null)
|
||||
throw new NullPointerException("The URI cannot be null, use \"\".");
|
||||
if (name == null)
|
||||
throw new NullPointerException("Element must have a name.");
|
||||
this.uri = uri;
|
||||
this.name = name;
|
||||
this.hashCode = toHashCode(uri, name);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getURI() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e == null)
|
||||
return false;
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
OpenElementEventNSImpl oee = (OpenElementEventNSImpl)e;
|
||||
if (!oee.uri.equals(this.uri))
|
||||
return false;
|
||||
if (!oee.name.equals(this.name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "openElement: " + this.name + " [" + this.uri + "]";
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.openElement(this.uri, this.name, false);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) {
|
||||
return xml.append('<').append(this.name).append('>');
|
||||
}
|
||||
|
||||
private int toHashCode(String uri, String name) {
|
||||
int hash = 107;
|
||||
hash = hash * 13 + ((uri != null) ? uri.hashCode() : 0);
|
||||
hash = hash * 13 + ((name != null) ? name.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class ProcessingInstructionEvent extends DiffXEventBase implements DiffXEvent {
|
||||
private final String target;
|
||||
|
||||
private final String data;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public ProcessingInstructionEvent(String target, String data) throws NullPointerException {
|
||||
this.target = target;
|
||||
this.data = data;
|
||||
this.hashCode = toHashCode(target, data);
|
||||
}
|
||||
|
||||
public String getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
ProcessingInstructionEvent pi = (ProcessingInstructionEvent)e;
|
||||
return (pi.target.equals(this.target) && pi.data.equals(this.data));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "pi: " + this.target + ": " + this.data;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
xml.writePI(this.target, this.data);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
xml.append("<?");
|
||||
xml.append(this.target);
|
||||
xml.append(' ');
|
||||
xml.append(this.data);
|
||||
xml.append("?>");
|
||||
return xml;
|
||||
}
|
||||
|
||||
private static int toHashCode(String s1, String s2) {
|
||||
int hash = 7;
|
||||
hash = hash * 103 + ((s1 != null) ? s1.hashCode() : 0);
|
||||
hash = hash * 103 + ((s2 != null) ? s2.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
|
||||
public final class SpaceEvent extends CharactersEventBase implements TextEvent {
|
||||
public static final SpaceEvent SINGLE_WHITESPACE = new SpaceEvent(" ");
|
||||
|
||||
public static final SpaceEvent DOUBLE_WHITESPACE = new SpaceEvent(" ");
|
||||
|
||||
public static final SpaceEvent NEW_LINE = new SpaceEvent("\n");
|
||||
|
||||
public static final SpaceEvent TAB = new SpaceEvent("\t");
|
||||
|
||||
public SpaceEvent(CharSequence w) throws NullPointerException {
|
||||
super(w);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "space: \"" + toString(getCharacters().toCharArray()) + '"';
|
||||
}
|
||||
|
||||
public static SpaceEvent getInstance(CharSequence space) {
|
||||
if (" ".equals(space))
|
||||
return SINGLE_WHITESPACE;
|
||||
if (" ".equals(space))
|
||||
return DOUBLE_WHITESPACE;
|
||||
if ("\n".equals(space))
|
||||
return NEW_LINE;
|
||||
if ("\t".equals(space))
|
||||
return TAB;
|
||||
return new SpaceEvent(space);
|
||||
}
|
||||
|
||||
public static SpaceEvent getInstance(char c) {
|
||||
if (c == ' ')
|
||||
return SINGLE_WHITESPACE;
|
||||
if (c == '\n')
|
||||
return NEW_LINE;
|
||||
if (c == '\t')
|
||||
return TAB;
|
||||
return new SpaceEvent(c + "");
|
||||
}
|
||||
|
||||
private static String toString(char[] chars) {
|
||||
StringBuffer out = new StringBuffer();
|
||||
for (char c : chars) {
|
||||
switch (c) {
|
||||
case '\n':
|
||||
out.append("\\n");
|
||||
break;
|
||||
case '\t':
|
||||
out.append("\\t");
|
||||
break;
|
||||
default:
|
||||
out.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
|
||||
public final class WordEvent extends CharactersEventBase implements TextEvent {
|
||||
public WordEvent(CharSequence w) throws NullPointerException {
|
||||
super(w);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "word: \"" + getCharacters() + '"';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.topologi.diffx.event.impl;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class XMLBranchEvent extends DiffXEventBase implements DiffXEvent {
|
||||
private final DiffXEvent[] branch;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public XMLBranchEvent(DiffXEvent[] events) {
|
||||
this.branch = events;
|
||||
this.hashCode = toHashCode(events);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(DiffXEvent e) {
|
||||
if (e.getClass() != getClass())
|
||||
return false;
|
||||
if (e.hashCode() != this.hashCode)
|
||||
return false;
|
||||
XMLBranchEvent be = (XMLBranchEvent)e;
|
||||
if (this.branch.length != be.branch.length)
|
||||
return false;
|
||||
for (int i = 0; i < this.branch.length; i++) {
|
||||
if (!be.branch[i].equals(this.branch[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void toXML(XMLWriter xml) throws IOException {
|
||||
for (DiffXEvent element : this.branch)
|
||||
element.toXML(xml);
|
||||
}
|
||||
|
||||
public StringBuffer toXML(StringBuffer xml) throws NullPointerException {
|
||||
for (DiffXEvent element : this.branch)
|
||||
element.toXML(xml);
|
||||
return xml;
|
||||
}
|
||||
|
||||
private static int toHashCode(DiffXEvent[] events) {
|
||||
int hash = 17;
|
||||
for (DiffXEvent e : events)
|
||||
hash = hash * 13 + ((e != null) ? e.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.event.impl.ProcessingInstructionEvent;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import com.topologi.diffx.xml.XMLWriterNSImpl;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Stack;
|
||||
|
||||
public final class BasicXMLFormatter implements XMLDiffXFormatter {
|
||||
private final XMLWriter xml;
|
||||
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
private transient boolean writeXMLDeclaration = true;
|
||||
|
||||
private transient boolean isSetup = false;
|
||||
|
||||
private transient short textFormat = 0;
|
||||
|
||||
private transient Stack<AttributeEvent> insAttributes = new Stack<AttributeEvent>();
|
||||
|
||||
private transient Stack<AttributeEvent> delAttributes = new Stack<AttributeEvent>();
|
||||
|
||||
public BasicXMLFormatter(Writer w) throws NullPointerException {
|
||||
if (w == null)
|
||||
throw new NullPointerException("The XML formatter requires a writer");
|
||||
this.xml = new XMLWriterNSImpl(w, false);
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException {
|
||||
if (!this.isSetup)
|
||||
setUpXML();
|
||||
endTextChange();
|
||||
if (!(e instanceof AttributeEvent))
|
||||
flushAttributes();
|
||||
e.toXML(this.xml);
|
||||
if (e instanceof com.topologi.diffx.event.TextEvent &&
|
||||
this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException {
|
||||
change(e, 1);
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException {
|
||||
change(e, -1);
|
||||
}
|
||||
|
||||
private void change(DiffXEvent e, int mod) throws IOException {
|
||||
if (!this.isSetup)
|
||||
setUpXML();
|
||||
if (e instanceof OpenElementEvent) {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
this.xml.openElement((mod > 0) ? "http://www.topologi.com/2005/Diff-X/Insert" : "http://www.topologi.com/2005/Diff-X/Delete", "element", false);
|
||||
this.xml.attribute("name", ((OpenElementEvent)e).getName());
|
||||
this.xml.attribute("ns-uri", ((OpenElementEvent)e).getURI());
|
||||
} else if (e instanceof com.topologi.diffx.event.CloseElementEvent) {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
this.xml.closeElement();
|
||||
} else if (e instanceof com.topologi.diffx.event.TextEvent) {
|
||||
flushAttributes();
|
||||
switchTextChange(mod);
|
||||
e.toXML(this.xml);
|
||||
if (this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
if (mod > 0) {
|
||||
this.insAttributes.push((AttributeEvent)e);
|
||||
} else {
|
||||
this.delAttributes.push((AttributeEvent)e);
|
||||
}
|
||||
} else if (e instanceof ProcessingInstructionEvent) {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
this.xml.openElement((mod > 0) ? "http://www.topologi.com/2005/Diff-X/Insert" : "http://www.topologi.com/2005/Diff-X/Delete", "processing-instruction", false);
|
||||
this.xml.attribute("data", ((ProcessingInstructionEvent)e).getData());
|
||||
this.xml.attribute("target", ((ProcessingInstructionEvent)e).getTarget());
|
||||
} else {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
e.toXML(this.xml);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void setWriteXMLDeclaration(boolean show) {
|
||||
this.writeXMLDeclaration = show;
|
||||
}
|
||||
|
||||
public void declarePrefixMapping(PrefixMapping mapping) {
|
||||
for (Enumeration<String> uris = mapping.getURIs(); uris.hasMoreElements(); ) {
|
||||
String uri = uris.nextElement();
|
||||
this.xml.setPrefixMapping(uri, mapping.getPrefix(uri));
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpXML() throws IOException {
|
||||
if (this.writeXMLDeclaration)
|
||||
this.xml.xmlDecl();
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X/Delete", "del");
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X/Insert", "ins");
|
||||
this.writeXMLDeclaration = false;
|
||||
this.isSetup = true;
|
||||
}
|
||||
|
||||
private void endTextChange() throws IOException {
|
||||
if (this.textFormat != 0) {
|
||||
this.xml.closeElement();
|
||||
this.textFormat = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void switchTextChange(int mod) throws IOException {
|
||||
if (mod > 0) {
|
||||
if (this.textFormat < 0)
|
||||
this.xml.closeElement();
|
||||
if (this.textFormat <= 0) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X/Insert", "text", false);
|
||||
this.textFormat = 1;
|
||||
}
|
||||
} else {
|
||||
if (this.textFormat > 0)
|
||||
this.xml.closeElement();
|
||||
if (this.textFormat >= 0) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X/Delete", "text", false);
|
||||
this.textFormat = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void flushAttributes() throws IOException {
|
||||
flushAttributes(this.insAttributes, "http://www.topologi.com/2005/Diff-X/Insert");
|
||||
flushAttributes(this.delAttributes, "http://www.topologi.com/2005/Diff-X/Delete");
|
||||
}
|
||||
|
||||
private void flushAttributes(Stack<AttributeEvent> atts, String uri) throws IOException {
|
||||
while (!atts.empty()) {
|
||||
AttributeEvent att = atts.pop();
|
||||
this.xml.openElement(uri, "attribute", false);
|
||||
this.xml.attribute("name", att.getName());
|
||||
if (att.getURI() != null)
|
||||
this.xml.attribute("ns-uri", att.getURI());
|
||||
this.xml.attribute("value", att.getValue());
|
||||
this.xml.closeElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import com.topologi.diffx.xml.XMLWriterNSImpl;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Stack;
|
||||
|
||||
public final class ConvenientXMLFormatter implements XMLDiffXFormatter {
|
||||
private final XMLWriter xml;
|
||||
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
private transient boolean writeXMLDeclaration = true;
|
||||
|
||||
private transient boolean isSetup = false;
|
||||
|
||||
private transient short textFormat = 0;
|
||||
|
||||
private transient Stack<AttributeEvent> insAttributes = new Stack<AttributeEvent>();
|
||||
|
||||
private transient Stack<AttributeEvent> delAttributes = new Stack<AttributeEvent>();
|
||||
|
||||
public ConvenientXMLFormatter(Writer w) throws NullPointerException {
|
||||
if (w == null)
|
||||
throw new NullPointerException("The XML formatter requires a writer");
|
||||
this.xml = new XMLWriterNSImpl(w, false);
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException {
|
||||
if (!this.isSetup)
|
||||
setUpXML();
|
||||
endTextChange();
|
||||
if (!(e instanceof AttributeEvent))
|
||||
flushAttributes();
|
||||
e.toXML(this.xml);
|
||||
if (e instanceof com.topologi.diffx.event.TextEvent &&
|
||||
this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException {
|
||||
change(e, 1);
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException {
|
||||
change(e, -1);
|
||||
}
|
||||
|
||||
private void change(DiffXEvent e, int mod) throws IOException {
|
||||
if (!this.isSetup)
|
||||
setUpXML();
|
||||
if (e instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("http://www.topologi.com/2005/Diff-X", (mod > 0) ? "insert" : "delete", "true");
|
||||
} else if (e instanceof com.topologi.diffx.event.CloseElementEvent) {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
this.xml.closeElement();
|
||||
} else if (e instanceof com.topologi.diffx.event.TextEvent) {
|
||||
flushAttributes();
|
||||
switchTextChange(mod);
|
||||
e.toXML(this.xml);
|
||||
if (this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
if (mod > 0) {
|
||||
e.toXML(this.xml);
|
||||
this.insAttributes.push((AttributeEvent)e);
|
||||
} else {
|
||||
this.delAttributes.push((AttributeEvent)e);
|
||||
}
|
||||
} else {
|
||||
flushAttributes();
|
||||
endTextChange();
|
||||
e.toXML(this.xml);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void setWriteXMLDeclaration(boolean show) {
|
||||
this.writeXMLDeclaration = show;
|
||||
}
|
||||
|
||||
public void declarePrefixMapping(PrefixMapping mapping) {
|
||||
for (Enumeration<String> uris = mapping.getURIs(); uris.hasMoreElements(); ) {
|
||||
String uri = uris.nextElement();
|
||||
this.xml.setPrefixMapping(uri, mapping.getPrefix(uri));
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpXML() throws IOException {
|
||||
if (this.writeXMLDeclaration)
|
||||
this.xml.xmlDecl();
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X", "dfx");
|
||||
this.writeXMLDeclaration = false;
|
||||
this.isSetup = true;
|
||||
}
|
||||
|
||||
private void endTextChange() throws IOException {
|
||||
if (this.textFormat != 0) {
|
||||
this.xml.closeElement();
|
||||
this.textFormat = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void switchTextChange(int mod) throws IOException {
|
||||
if (mod > 0) {
|
||||
if (this.textFormat < 0)
|
||||
this.xml.closeElement();
|
||||
if (this.textFormat <= 0) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", "ins", false);
|
||||
this.textFormat = 1;
|
||||
}
|
||||
} else {
|
||||
if (this.textFormat > 0)
|
||||
this.xml.closeElement();
|
||||
if (this.textFormat >= 0) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", "del", false);
|
||||
this.textFormat = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void flushAttributes() throws IOException {
|
||||
flushAttributes(this.insAttributes, 1);
|
||||
flushAttributes(this.delAttributes, -1);
|
||||
}
|
||||
|
||||
private void flushAttributes(Stack<AttributeEvent> atts, int mod) throws IOException {
|
||||
while (!atts.empty()) {
|
||||
AttributeEvent att = atts.pop();
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", (mod > 0) ? "ins" : "del", false);
|
||||
this.xml.attribute(att.getURI(), att.getName(), att.getValue());
|
||||
this.xml.closeElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface DiffXFormatter {
|
||||
void format(DiffXEvent paramDiffXEvent) throws IOException, IllegalStateException;
|
||||
|
||||
void insert(DiffXEvent paramDiffXEvent) throws IOException, IllegalStateException;
|
||||
|
||||
void delete(DiffXEvent paramDiffXEvent) throws IOException, IllegalStateException;
|
||||
|
||||
void setConfig(DiffXConfig paramDiffXConfig);
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class MultiplexFormatter implements DiffXFormatter {
|
||||
private final List<DiffXFormatter> formatters;
|
||||
|
||||
public MultiplexFormatter() {
|
||||
this.formatters = new ArrayList<DiffXFormatter>();
|
||||
}
|
||||
|
||||
public MultiplexFormatter(DiffXFormatter f) {
|
||||
this.formatters = new ArrayList<DiffXFormatter>(1);
|
||||
this.formatters.add(f);
|
||||
}
|
||||
|
||||
public void add(DiffXFormatter f) {
|
||||
this.formatters.add(f);
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException {
|
||||
for (DiffXFormatter f : this.formatters)
|
||||
f.format(e);
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException {
|
||||
for (DiffXFormatter f : this.formatters)
|
||||
f.insert(e);
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException, IllegalStateException {
|
||||
for (DiffXFormatter f : this.formatters)
|
||||
f.delete(e);
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
for (DiffXFormatter f : this.formatters)
|
||||
f.setConfig(config);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.config.WhiteSpaceProcessing;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.impl.SpaceEvent;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import com.topologi.diffx.xml.XMLWriterNSImpl;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public final class SafeXMLFormatter implements XMLDiffXFormatter {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final XMLWriter xml;
|
||||
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
private transient boolean writeXMLDeclaration = true;
|
||||
|
||||
public SafeXMLFormatter() throws IOException {
|
||||
this(new PrintWriter(System.out));
|
||||
}
|
||||
|
||||
public SafeXMLFormatter(Writer w) throws IOException {
|
||||
this.xml = new XMLWriterNSImpl(w, false);
|
||||
if (this.writeXMLDeclaration) {
|
||||
this.xml.xmlDecl();
|
||||
this.writeXMLDeclaration = false;
|
||||
}
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X", "dfx");
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X/Delete", "del");
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X/Insert", "ins");
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException {
|
||||
e.toXML(this.xml);
|
||||
if (e instanceof com.topologi.diffx.event.impl.CharactersEventBase &&
|
||||
this.config.getWhiteSpaceProcessing() == WhiteSpaceProcessing.IGNORE)
|
||||
this.xml.writeXML(" ");
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException {
|
||||
if (e instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("dfx:insert", "true");
|
||||
} else if (e == SpaceEvent.NEW_LINE) {
|
||||
e.toXML(this.xml);
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharactersEventBase) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", "ins", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
if (this.config.getWhiteSpaceProcessing() == WhiteSpaceProcessing.IGNORE)
|
||||
this.xml.writeXML(" ");
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("ins:" + ((AttributeEvent)e).getName(), "true");
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharEvent) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", "ins", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
} else {
|
||||
e.toXML(this.xml);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException {
|
||||
if (e instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("dfx:delete", "true");
|
||||
} else if (e == SpaceEvent.NEW_LINE) {
|
||||
e.toXML(this.xml);
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharactersEventBase) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", "del", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
if (this.config.getWhiteSpaceProcessing() == WhiteSpaceProcessing.IGNORE)
|
||||
this.xml.writeXML(" ");
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
this.xml.attribute("del:" + ((AttributeEvent)e).getName(), ((AttributeEvent)e).getValue());
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharEvent) {
|
||||
this.xml.openElement("http://www.topologi.com/2005/Diff-X", "del", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
} else {
|
||||
e.toXML(this.xml);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void setWriteXMLDeclaration(boolean show) {
|
||||
this.writeXMLDeclaration = show;
|
||||
}
|
||||
|
||||
public void declarePrefixMapping(PrefixMapping mapping) {
|
||||
for (Enumeration<String> uris = mapping.getURIs(); uris.hasMoreElements(); ) {
|
||||
String uri = uris.nextElement();
|
||||
this.xml.setPrefixMapping(uri, mapping.getPrefix(uri));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.event.impl.CharactersEventBase;
|
||||
import com.topologi.diffx.event.impl.LineEvent;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
public final class ShortStringFormatter implements DiffXFormatter {
|
||||
private final Writer out;
|
||||
|
||||
public ShortStringFormatter() throws IOException {
|
||||
this(new PrintWriter(System.out));
|
||||
}
|
||||
|
||||
public ShortStringFormatter(Writer w) throws IOException {
|
||||
this.out = w;
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException, IllegalStateException {
|
||||
this.out.write(toShortString(e));
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException, IllegalStateException {
|
||||
this.out.write("+");
|
||||
this.out.write(toShortString(e));
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException, IllegalStateException {
|
||||
this.out.write("-");
|
||||
this.out.write(toShortString(e));
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {}
|
||||
|
||||
public static String toShortString(DiffXEvent e) {
|
||||
if (e instanceof OpenElementEvent)
|
||||
return '<' + ((OpenElementEvent)e).getName() + '>';
|
||||
if (e instanceof CloseElementEvent)
|
||||
return "</" + ((CloseElementEvent)e).getName() + '>';
|
||||
if (e instanceof AttributeEvent)
|
||||
return "@" + ((AttributeEvent)e).getName();
|
||||
if (e instanceof com.topologi.diffx.event.impl.WordEvent)
|
||||
return '"' + ((CharactersEventBase)e).getCharacters() + '"';
|
||||
if (e instanceof com.topologi.diffx.event.impl.SpaceEvent)
|
||||
return "_s_";
|
||||
if (e instanceof com.topologi.diffx.event.impl.CharEvent)
|
||||
return '\'' + ((CharactersEventBase)e).getCharacters() + '\'';
|
||||
if (e instanceof com.topologi.diffx.event.impl.IgnorableSpaceEvent)
|
||||
return "_i_";
|
||||
if (e instanceof LineEvent)
|
||||
return "L#" + ((LineEvent)e).getLineNumber();
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.impl.SpaceEvent;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import com.topologi.diffx.xml.XMLWriterNSImpl;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public final class SmartXMLFormatter implements XMLDiffXFormatter {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final XMLWriter xml;
|
||||
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
private transient boolean writeXMLDeclaration = true;
|
||||
|
||||
public SmartXMLFormatter() throws IOException {
|
||||
this(new PrintWriter(System.out));
|
||||
}
|
||||
|
||||
public SmartXMLFormatter(Writer w) throws IOException {
|
||||
this.xml = new XMLWriterNSImpl(w, false);
|
||||
if (this.writeXMLDeclaration) {
|
||||
this.xml.xmlDecl();
|
||||
this.writeXMLDeclaration = false;
|
||||
}
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X", "dfx");
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X/Delete", "del");
|
||||
this.xml.setPrefixMapping("http://www.topologi.com/2005/Diff-X/Insert", "ins");
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException {
|
||||
e.toXML(this.xml);
|
||||
if (e instanceof com.topologi.diffx.event.impl.CharactersEventBase &&
|
||||
this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException {
|
||||
if (e instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("dfx:insert", "true");
|
||||
} else if (e == SpaceEvent.NEW_LINE) {
|
||||
e.toXML(this.xml);
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharactersEventBase) {
|
||||
this.xml.openElement("ins", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
if (this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("ins:" + ((AttributeEvent)e).getName(), "true");
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharEvent) {
|
||||
this.xml.openElement("ins", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
} else {
|
||||
e.toXML(this.xml);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException {
|
||||
if (e instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
e.toXML(this.xml);
|
||||
this.xml.attribute("dfx:delete", "true");
|
||||
} else if (e == SpaceEvent.NEW_LINE) {
|
||||
e.toXML(this.xml);
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharactersEventBase) {
|
||||
this.xml.openElement("del", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
if (this.config.isIgnoreWhiteSpace() && !this.config.isPreserveWhiteSpace())
|
||||
this.xml.writeXML(" ");
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
this.xml.attribute("del:" + ((AttributeEvent)e).getName(), ((AttributeEvent)e).getValue());
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.CharEvent) {
|
||||
this.xml.openElement("del", false);
|
||||
e.toXML(this.xml);
|
||||
this.xml.closeElement();
|
||||
} else {
|
||||
e.toXML(this.xml);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void setWriteXMLDeclaration(boolean show) {
|
||||
this.writeXMLDeclaration = show;
|
||||
}
|
||||
|
||||
public void declarePrefixMapping(PrefixMapping mapping) {
|
||||
for (Enumeration<String> uris = mapping.getURIs(); uris.hasMoreElements(); ) {
|
||||
String uri = uris.nextElement();
|
||||
this.xml.setPrefixMapping(uri, mapping.getPrefix(uri));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.event.impl.CharEvent;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public final class StrictXMLFormatter implements XMLDiffXFormatter {
|
||||
private final PrintWriter xml;
|
||||
|
||||
private String openDel = "<del>";
|
||||
|
||||
private String closeDel = "</del>";
|
||||
|
||||
private String openIns = "<ins>";
|
||||
|
||||
private String closeIns = "</ins>";
|
||||
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
private transient boolean declareNamespace = true;
|
||||
|
||||
private transient boolean isInserting = false;
|
||||
|
||||
private transient boolean isDeleting = false;
|
||||
|
||||
private transient boolean isElementNude = false;
|
||||
|
||||
public StrictXMLFormatter() {
|
||||
this.xml = new PrintWriter(System.out);
|
||||
init();
|
||||
}
|
||||
|
||||
public StrictXMLFormatter(Writer w) {
|
||||
this.xml = new PrintWriter(w);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
this.xml.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||
}
|
||||
|
||||
public void format(DiffXEvent e) throws IOException {
|
||||
if (e instanceof OpenElementEvent) {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isInserting)
|
||||
closeIns();
|
||||
if (this.isDeleting)
|
||||
closeDel();
|
||||
OpenElementEvent oee = (OpenElementEvent)e;
|
||||
this.xml.print('<' + oee.getName());
|
||||
if (this.declareNamespace) {
|
||||
this.xml.print(" xmlns:dfx=\"http://www.topologi.com/2005/Diff-X\"");
|
||||
this.declareNamespace = false;
|
||||
}
|
||||
this.isElementNude = true;
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isInserting)
|
||||
closeIns();
|
||||
if (this.isDeleting)
|
||||
closeDel();
|
||||
this.xml.print(e.toXML());
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
if (this.isElementNude) {
|
||||
this.xml.print(e.toXML());
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot write an attribute once the element is closed");
|
||||
}
|
||||
} else {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isInserting)
|
||||
closeIns();
|
||||
if (this.isDeleting)
|
||||
closeDel();
|
||||
if (e instanceof com.topologi.diffx.event.impl.WordEvent || e instanceof com.topologi.diffx.event.impl.SpaceEvent) {
|
||||
this.xml.print(e.toXML());
|
||||
} else if (e instanceof CharEvent) {
|
||||
this.xml.print(((CharEvent)e).c);
|
||||
}
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void insert(DiffXEvent e) throws IOException {
|
||||
if (e instanceof OpenElementEvent) {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isDeleting)
|
||||
closeDel();
|
||||
OpenElementEvent oee = (OpenElementEvent)e;
|
||||
this.xml.print('<' + oee.getName());
|
||||
if (this.declareNamespace)
|
||||
this.xml.print(" xmlns:dfx=\"http://www.allette.com.au/diffex\"");
|
||||
this.xml.print(" dfx:insert=\"true\"");
|
||||
this.isElementNude = true;
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isDeleting)
|
||||
closeDel();
|
||||
this.xml.print("</");
|
||||
this.xml.print(((CloseElementEvent)e).getName());
|
||||
this.xml.print('>');
|
||||
} else if (e instanceof AttributeEvent) {
|
||||
if (this.isElementNude) {
|
||||
this.xml.print(" ");
|
||||
this.xml.print(((AttributeEvent)e).getName());
|
||||
this.xml.print("=\"");
|
||||
this.xml.print(((AttributeEvent)e).getValue());
|
||||
this.xml.print('"');
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot insert an attribute once the element is closed");
|
||||
}
|
||||
} else {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isDeleting)
|
||||
closeDel();
|
||||
if (e instanceof com.topologi.diffx.event.impl.WordEvent) {
|
||||
if (!this.isInserting)
|
||||
openIns();
|
||||
this.xml.print(e.toXML());
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.SpaceEvent) {
|
||||
this.xml.print(e.toXML());
|
||||
} else if (e instanceof CharEvent) {
|
||||
this.xml.print(((CharEvent)e).c);
|
||||
}
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void delete(DiffXEvent e) throws IOException, IllegalStateException {
|
||||
if (this.isElementNude)
|
||||
denudeElement();
|
||||
if (this.isInserting)
|
||||
closeIns();
|
||||
if (e instanceof OpenElementEvent) {
|
||||
OpenElementEvent oee = (OpenElementEvent)e;
|
||||
this.xml.print('<' + oee.getName());
|
||||
if (this.declareNamespace)
|
||||
this.xml.print(" xmlns:dfx=\"http://www.allette.com.au/diffex\"");
|
||||
this.xml.print(" dfx:delete=\"true\"");
|
||||
this.xml.print('>');
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
this.xml.print("</");
|
||||
this.xml.print(((CloseElementEvent)e).getName());
|
||||
this.xml.print('>');
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.WordEvent) {
|
||||
if (!this.isDeleting)
|
||||
openDel();
|
||||
this.xml.print(e.toXML());
|
||||
} else if (e instanceof com.topologi.diffx.event.impl.SpaceEvent) {
|
||||
this.xml.print(e.toXML());
|
||||
} else if (e instanceof CharEvent) {
|
||||
this.xml.print(((CharEvent)e).c);
|
||||
}
|
||||
this.xml.flush();
|
||||
}
|
||||
|
||||
public void setInsertTags(String start, String end) throws NullPointerException {
|
||||
if (start == null)
|
||||
throw new NullPointerException("The start element for inserted text must have a value");
|
||||
if (end == null)
|
||||
throw new NullPointerException("The start element for inserted text must have a value");
|
||||
this.openIns = start;
|
||||
this.closeIns = end;
|
||||
}
|
||||
|
||||
public void setDeleteTags(String start, String end) throws NullPointerException {
|
||||
if (start == null)
|
||||
throw new NullPointerException("The start element for deleted text must have a value");
|
||||
if (end == null)
|
||||
throw new NullPointerException("The start element for deleted text must have a value");
|
||||
this.openDel = start;
|
||||
this.closeDel = end;
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void setWriteXMLDeclaration(boolean show) {}
|
||||
|
||||
public void declarePrefixMapping(PrefixMapping mapping) {
|
||||
for (Enumeration<String> uris = mapping.getURIs(); uris.hasMoreElements(); ) {
|
||||
String uri = uris.nextElement();
|
||||
mapping.getPrefix(uri);
|
||||
}
|
||||
}
|
||||
|
||||
private void openIns() {
|
||||
this.xml.print(this.openIns);
|
||||
this.isInserting = true;
|
||||
}
|
||||
|
||||
private void openDel() {
|
||||
this.xml.print(this.openDel);
|
||||
this.isDeleting = true;
|
||||
}
|
||||
|
||||
private void closeIns() {
|
||||
this.xml.print(this.closeIns);
|
||||
this.isInserting = false;
|
||||
}
|
||||
|
||||
private void closeDel() {
|
||||
this.xml.print(this.closeDel);
|
||||
this.isDeleting = false;
|
||||
}
|
||||
|
||||
private void denudeElement() {
|
||||
this.xml.print(">");
|
||||
this.isElementNude = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.topologi.diffx.format;
|
||||
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
|
||||
public interface XMLDiffXFormatter extends DiffXFormatter {
|
||||
void setWriteXMLDeclaration(boolean paramBoolean);
|
||||
|
||||
void declarePrefixMapping(PrefixMapping paramPrefixMapping);
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.impl.AttributeEventImpl;
|
||||
import com.topologi.diffx.event.impl.AttributeEventNSImpl;
|
||||
import java.util.Comparator;
|
||||
|
||||
final class AttributeComparator implements Comparator<AttributeEvent> {
|
||||
public int compare(AttributeEvent o1, AttributeEvent o2) throws ClassCastException {
|
||||
if (o1 instanceof AttributeEventImpl && o2 instanceof AttributeEventImpl)
|
||||
return compare((AttributeEventImpl)o1, (AttributeEventImpl)o2);
|
||||
if (o1 instanceof AttributeEventNSImpl && o2 instanceof AttributeEventNSImpl)
|
||||
return compare((AttributeEventNSImpl)o1, (AttributeEventNSImpl)o2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int compare(AttributeEventImpl att1, AttributeEventImpl att2) {
|
||||
return att1.getName().compareTo(att2.getName());
|
||||
}
|
||||
|
||||
public int compare(AttributeEventNSImpl att1, AttributeEventNSImpl att2) {
|
||||
return toCName(att1).compareTo(toCName(att2));
|
||||
}
|
||||
|
||||
private static String toCName(AttributeEventNSImpl att) {
|
||||
return (att.getURI() != null) ? (att.getURI() + ':' + att.getName()) : att.getName();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.event.impl.EventFactory;
|
||||
import com.topologi.diffx.event.impl.ProcessingInstructionEvent;
|
||||
import com.topologi.diffx.load.text.TextTokenizer;
|
||||
import com.topologi.diffx.load.text.TokenizerFactory;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import com.topologi.diffx.sequence.PrefixMapping;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.ProcessingInstruction;
|
||||
import org.w3c.dom.Text;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
public final class DOMRecorder implements XMLRecorder {
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
private transient EventFactory efactory;
|
||||
|
||||
private transient TextTokenizer tokenizer;
|
||||
|
||||
private transient EventSequence sequence;
|
||||
|
||||
private transient PrefixMapping mapping;
|
||||
|
||||
private transient int currentWeight = -1;
|
||||
|
||||
private transient List<Integer> weights = new ArrayList<Integer>();
|
||||
|
||||
private transient boolean isFragment = true;
|
||||
|
||||
public DiffXConfig getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public EventSequence process(File file) throws LoadingException, IOException {
|
||||
InputStream in = new BufferedInputStream(new FileInputStream(file));
|
||||
return process(new InputSource(in));
|
||||
}
|
||||
|
||||
public EventSequence process(String xml) throws LoadingException {
|
||||
return process(new InputSource(new StringReader(xml)));
|
||||
}
|
||||
|
||||
public EventSequence process(InputSource is) throws LoadingException {
|
||||
this.isFragment = false;
|
||||
try {
|
||||
DocumentBuilder builder = XmlUtils.getNewDocumentBuilder();
|
||||
Document document = builder.parse(is);
|
||||
return process(document);
|
||||
} catch (Exception ex) {
|
||||
throw new LoadingException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public EventSequence process(Node node) throws LoadingException {
|
||||
this.efactory = new EventFactory(this.config.isNamespaceAware());
|
||||
this.tokenizer = TokenizerFactory.get(this.config);
|
||||
this.sequence = new EventSequence();
|
||||
this.mapping = this.sequence.getPrefixMapping();
|
||||
loadNode(node);
|
||||
this.isFragment = true;
|
||||
return this.sequence;
|
||||
}
|
||||
|
||||
public EventSequence process(NodeList node) throws LoadingException {
|
||||
if (node.getLength() == 0)
|
||||
return new EventSequence();
|
||||
return process(node.item(0));
|
||||
}
|
||||
|
||||
private void loadNode(Node node) throws LoadingException {
|
||||
if (node instanceof Element)
|
||||
load((Element)node);
|
||||
if (node instanceof Text) {
|
||||
load((Text)node);
|
||||
} else if (node instanceof Attr) {
|
||||
load((Attr)node);
|
||||
} else if (node instanceof Document) {
|
||||
load((Document)node);
|
||||
} else if (node instanceof ProcessingInstruction) {
|
||||
load((ProcessingInstruction)node);
|
||||
}
|
||||
}
|
||||
|
||||
private void load(Document document) throws LoadingException {
|
||||
load(document.getDocumentElement());
|
||||
}
|
||||
|
||||
private void load(Element element) throws LoadingException {
|
||||
if (this.currentWeight > 0)
|
||||
this.weights.add(Integer.valueOf(this.currentWeight));
|
||||
this.currentWeight = 1;
|
||||
OpenElementEvent open = null;
|
||||
if (this.config.isNamespaceAware()) {
|
||||
String uri = (element.getNamespaceURI() == null) ? "" : element.getNamespaceURI();
|
||||
String name = element.getLocalName();
|
||||
handlePrefixMapping(uri, element.getPrefix());
|
||||
open = this.efactory.makeOpenElement(uri, name);
|
||||
} else {
|
||||
open = this.efactory.makeOpenElement(null, element.getNodeName());
|
||||
}
|
||||
this.sequence.addEvent(open);
|
||||
NamedNodeMap atts = element.getAttributes();
|
||||
if (atts.getLength() == 1) {
|
||||
load((Attr)atts.item(0));
|
||||
} else if (atts.getLength() > 1) {
|
||||
String[] names = new String[atts.getLength()];
|
||||
for (int j = 0; j < atts.getLength(); j++) {
|
||||
Attr attr = (Attr)atts.item(j);
|
||||
names[j] = attr.getName();
|
||||
}
|
||||
Arrays.sort(names);
|
||||
for (String name : names)
|
||||
load((Attr)atts.getNamedItem(name));
|
||||
}
|
||||
NodeList list = element.getChildNodes();
|
||||
for (int i = 0; i < list.getLength(); i++)
|
||||
loadNode(list.item(i));
|
||||
CloseElementEvent close = this.efactory.makeCloseElement(open);
|
||||
this.sequence.addEvent(close);
|
||||
close.setWeight(this.currentWeight);
|
||||
open.setWeight(this.currentWeight);
|
||||
this.currentWeight += popWeight();
|
||||
}
|
||||
|
||||
private void load(Text text) throws LoadingException {
|
||||
List<TextEvent> events = this.tokenizer.tokenize(text.getData());
|
||||
for (TextEvent e : events)
|
||||
this.sequence.addEvent(e);
|
||||
this.currentWeight += events.size();
|
||||
}
|
||||
|
||||
private void load(ProcessingInstruction pi) throws LoadingException {
|
||||
this.sequence.addEvent(new ProcessingInstructionEvent(pi.getTarget(), pi.getData()));
|
||||
this.currentWeight++;
|
||||
}
|
||||
|
||||
private int popWeight() {
|
||||
if (this.weights.size() > 0)
|
||||
return (Integer)this.weights.remove(this.weights.size() - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void load(Attr attr) {
|
||||
handlePrefixMapping(attr.getNamespaceURI(), attr.getPrefix());
|
||||
load(this.efactory.makeAttribute(attr.getNamespaceURI(), attr.getLocalName(), attr.getNodeName(), attr.getValue()));
|
||||
}
|
||||
|
||||
private void load(AttributeEvent e) {
|
||||
if ("http://www.w3.org/2000/xmlns/".equals(e.getURI())) {
|
||||
this.sequence.mapPrefix(e.getValue(), e.getName());
|
||||
} else {
|
||||
e.setWeight(2);
|
||||
this.currentWeight += 2;
|
||||
this.sequence.addEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePrefixMapping(String uri, String prefix) {
|
||||
if (this.isFragment) {
|
||||
if (this.mapping.getPrefix(uri) != null)
|
||||
return;
|
||||
if (prefix == null && !"".equals(uri)) {
|
||||
this.mapping.add(uri, "");
|
||||
} else if (prefix != null && !"xmlns".equals(prefix)) {
|
||||
this.mapping.add(uri, prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.DiffXException;
|
||||
|
||||
public final class LoadingException extends DiffXException {
|
||||
private static final long serialVersionUID = -5026953481292613087L;
|
||||
|
||||
public LoadingException() {}
|
||||
|
||||
public LoadingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public LoadingException(Exception ex) {
|
||||
super(ex);
|
||||
}
|
||||
|
||||
public LoadingException(String message, Exception ex) {
|
||||
super(message, ex);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Recorder {
|
||||
EventSequence process(File paramFile) throws LoadingException, IOException;
|
||||
|
||||
EventSequence process(String paramString) throws LoadingException, IOException;
|
||||
}
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.event.AttributeEvent;
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.event.impl.EventFactory;
|
||||
import com.topologi.diffx.event.impl.ProcessingInstructionEvent;
|
||||
import com.topologi.diffx.load.text.TextTokenizer;
|
||||
import com.topologi.diffx.load.text.TokenizerFactory;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
|
||||
public final class SAXRecorder implements XMLRecorder {
|
||||
private static XMLReader reader;
|
||||
|
||||
private static final String DEFAULT_XML_READER;
|
||||
|
||||
static {
|
||||
String str;
|
||||
try {
|
||||
str = XMLReaderFactory.createXMLReader().getClass().getName();
|
||||
} catch (SAXException ex) {
|
||||
str = "";
|
||||
}
|
||||
DEFAULT_XML_READER = str;
|
||||
}
|
||||
|
||||
private static String readerClassName = DEFAULT_XML_READER;
|
||||
|
||||
private static boolean newReader = true;
|
||||
|
||||
private DiffXConfig config = new DiffXConfig();
|
||||
|
||||
protected transient EventSequence sequence;
|
||||
|
||||
public EventSequence process(File file) throws LoadingException, IOException {
|
||||
InputStream in = new BufferedInputStream(new FileInputStream(file));
|
||||
EventSequence seq = null;
|
||||
seq = process(new InputSource(in));
|
||||
in.close();
|
||||
in = null;
|
||||
return seq;
|
||||
}
|
||||
|
||||
public EventSequence process(String xml) throws LoadingException, IOException {
|
||||
return process(new InputSource(new StringReader(xml)));
|
||||
}
|
||||
|
||||
public EventSequence process(InputSource is) throws LoadingException, IOException {
|
||||
if (reader == null || newReader)
|
||||
init();
|
||||
reader.setContentHandler(new RecorderHandler());
|
||||
reader.setErrorHandler(new RecorderErrorHandler());
|
||||
try {
|
||||
reader.setFeature("http://xml.org/sax/features/namespaces", this.config.isNamespaceAware());
|
||||
reader.setFeature("http://xml.org/sax/features/namespace-prefixes", this.config.isReportPrefixDifferences());
|
||||
reader.parse(is);
|
||||
} catch (SAXException ex) {
|
||||
throw new LoadingException(ex);
|
||||
}
|
||||
return this.sequence;
|
||||
}
|
||||
|
||||
public DiffXConfig getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public void setConfig(DiffXConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public static String getXMLReaderClass() {
|
||||
return readerClassName;
|
||||
}
|
||||
|
||||
public static void setXMLReaderClass(String className) {
|
||||
if (className == null)
|
||||
className = DEFAULT_XML_READER;
|
||||
newReader = !className.equals(readerClassName);
|
||||
readerClassName = className;
|
||||
}
|
||||
|
||||
private static void init() throws LoadingException {
|
||||
try {
|
||||
reader = XMLReaderFactory.createXMLReader(readerClassName);
|
||||
reader.setFeature("http://xml.org/sax/features/validation", false);
|
||||
} catch (SAXException ex) {
|
||||
throw new LoadingException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private final class RecorderHandler extends DefaultHandler {
|
||||
private final StringBuffer ch = new StringBuffer();
|
||||
|
||||
private final AttributeComparator comparator = new AttributeComparator();
|
||||
|
||||
private transient int currentWeight = -1;
|
||||
|
||||
private transient List<OpenElementEvent> openElements = new ArrayList<OpenElementEvent>();
|
||||
|
||||
private transient List<Integer> weights = new ArrayList<Integer>();
|
||||
|
||||
private transient EventFactory efactory;
|
||||
|
||||
private transient TextTokenizer tokenizer;
|
||||
|
||||
public void startDocument() {
|
||||
SAXRecorder.this.sequence = new EventSequence();
|
||||
this.efactory = new EventFactory(SAXRecorder.this.config.isNamespaceAware());
|
||||
this.tokenizer = TokenizerFactory.get(SAXRecorder.this.config);
|
||||
SAXRecorder.this.sequence.mapPrefix("http://www.w3.org/XML/1998/namespace", "xml");
|
||||
}
|
||||
|
||||
public void startPrefixMapping(String prefix, String uri) throws SAXException {
|
||||
SAXRecorder.this.sequence.mapPrefix(uri, prefix);
|
||||
}
|
||||
|
||||
public void startElement(String uri, String localName, String qName, Attributes atts) {
|
||||
recordCharacters();
|
||||
if (this.currentWeight > 0)
|
||||
this.weights.add(new Integer(this.currentWeight));
|
||||
this.currentWeight = 1;
|
||||
OpenElementEvent open = this.efactory.makeOpenElement(uri, localName, qName);
|
||||
this.openElements.add(open);
|
||||
SAXRecorder.this.sequence.addEvent(open);
|
||||
handleAttributes(atts);
|
||||
}
|
||||
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
recordCharacters();
|
||||
OpenElementEvent open = popLastOpenElement();
|
||||
open.setWeight(this.currentWeight);
|
||||
CloseElementEvent close = this.efactory.makeCloseElement(open);
|
||||
close.setWeight(this.currentWeight);
|
||||
SAXRecorder.this.sequence.addEvent(close);
|
||||
this.currentWeight += popWeight();
|
||||
}
|
||||
|
||||
public void characters(char[] buf, int pos, int len) {
|
||||
this.ch.append(buf, pos, len);
|
||||
}
|
||||
|
||||
public void ignorableWhitespace(char[] buf1, int pos, int len) {}
|
||||
|
||||
public void processingInstruction(String target, String data) {
|
||||
SAXRecorder.this.sequence.addEvent(new ProcessingInstructionEvent(target, data));
|
||||
this.currentWeight++;
|
||||
}
|
||||
|
||||
public void endDocument() throws SAXException {}
|
||||
|
||||
private void recordCharacters() {
|
||||
if (this.ch != null) {
|
||||
List<TextEvent> events = this.tokenizer.tokenize(this.ch);
|
||||
for (TextEvent e : events)
|
||||
SAXRecorder.this.sequence.addEvent(e);
|
||||
this.currentWeight += events.size();
|
||||
this.ch.setLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
private OpenElementEvent popLastOpenElement() {
|
||||
return (OpenElementEvent)this.openElements.remove(this.openElements.size() - 1);
|
||||
}
|
||||
|
||||
private int popWeight() {
|
||||
if (this.weights.size() > 0)
|
||||
return (Integer)this.weights.remove(this.weights.size() - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void handleAttributes(Attributes atts) {
|
||||
if (atts.getLength() == 1) {
|
||||
SAXRecorder.this.sequence.addEvent(this.efactory.makeAttribute(atts.getURI(0), atts.getLocalName(0), atts.getQName(0), atts.getValue(0)));
|
||||
} else if (atts.getLength() > 1) {
|
||||
AttributeEvent[] attEvents = new AttributeEvent[atts.getLength()];
|
||||
for (int i = 0; i < atts.getLength(); i++) {
|
||||
attEvents[i] = this.efactory.makeAttribute(atts.getURI(i), atts.getLocalName(i), atts.getQName(i), atts.getValue(i));
|
||||
attEvents[i].setWeight(2);
|
||||
this.currentWeight += 2;
|
||||
}
|
||||
Arrays.<AttributeEvent>sort(attEvents, this.comparator);
|
||||
for (AttributeEvent attEvent : attEvents)
|
||||
SAXRecorder.this.sequence.addEvent(attEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private RecorderHandler() {}
|
||||
}
|
||||
|
||||
private static final class RecorderErrorHandler implements ErrorHandler {
|
||||
private RecorderErrorHandler() {}
|
||||
|
||||
public void error(SAXParseException ex) throws SAXException {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
public void fatalError(SAXParseException ex) throws SAXException {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
public void warning(SAXParseException ex) throws SAXException {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.event.impl.LineEvent;
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
|
||||
public final class TextRecorder implements Recorder {
|
||||
public EventSequence process(File file) throws LoadingException, IOException {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(file));
|
||||
String line = reader.readLine();
|
||||
int count = 0;
|
||||
EventSequence seq = new EventSequence();
|
||||
while (line != null) {
|
||||
seq.addEvent(new LineEvent(line, ++count));
|
||||
line = reader.readLine();
|
||||
}
|
||||
reader.close();
|
||||
return seq;
|
||||
}
|
||||
|
||||
public EventSequence process(String text) throws LoadingException, IOException {
|
||||
BufferedReader reader = new BufferedReader(new StringReader(text));
|
||||
String line = reader.readLine();
|
||||
int count = 0;
|
||||
EventSequence seq = new EventSequence();
|
||||
while (line != null) {
|
||||
seq.addEvent(new LineEvent(line, ++count));
|
||||
line = reader.readLine();
|
||||
}
|
||||
return seq;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.topologi.diffx.load;
|
||||
|
||||
import com.topologi.diffx.sequence.EventSequence;
|
||||
import java.io.IOException;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
public interface XMLRecorder extends Recorder {
|
||||
EventSequence process(InputSource paramInputSource) throws LoadingException, IOException;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.topologi.diffx.load.text;
|
||||
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import java.util.List;
|
||||
|
||||
public interface TextTokenizer {
|
||||
List<TextEvent> tokenize(CharSequence paramCharSequence);
|
||||
|
||||
TextGranularity granurality();
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.topologi.diffx.load.text;
|
||||
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.event.impl.CharactersEvent;
|
||||
import com.topologi.diffx.event.impl.SpaceEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class TokenizerByChar implements TextTokenizer {
|
||||
private final Map<Character, TextEvent> recycling = new HashMap<Character, TextEvent>();
|
||||
|
||||
public List<TextEvent> tokenize(CharSequence seq) {
|
||||
if (seq == null)
|
||||
return null;
|
||||
if (seq.length() == 0)
|
||||
return Collections.<TextEvent>emptyList();
|
||||
List<TextEvent> events = new ArrayList<TextEvent>(seq.length());
|
||||
Character c = null;
|
||||
for (int i = 0; i < seq.length(); i++) {
|
||||
c = seq.charAt(i);
|
||||
TextEvent e = this.recycling.get(c);
|
||||
if (e == null)
|
||||
if (Character.isWhitespace(c.charValue())) {
|
||||
e = SpaceEvent.getInstance(c.charValue());
|
||||
} else {
|
||||
e = new CharactersEvent(c + "");
|
||||
}
|
||||
events.add(e);
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
public TextGranularity granurality() {
|
||||
return TextGranularity.CHARACTER;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package com.topologi.diffx.load.text;
|
||||
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
import com.topologi.diffx.config.WhiteSpaceProcessing;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.event.impl.CharactersEvent;
|
||||
import com.topologi.diffx.event.impl.IgnorableSpaceEvent;
|
||||
import com.topologi.diffx.event.impl.SpaceEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public final class TokenizerByText implements TextTokenizer {
|
||||
private final WhiteSpaceProcessing whitespace;
|
||||
|
||||
public TokenizerByText(WhiteSpaceProcessing whitespace) {
|
||||
if (whitespace == null)
|
||||
throw new NullPointerException("the white space processing must be specified.");
|
||||
this.whitespace = whitespace;
|
||||
}
|
||||
|
||||
public List<TextEvent> tokenize(CharSequence seq) {
|
||||
TextEvent e;
|
||||
if (seq == null)
|
||||
return null;
|
||||
if (seq.length() == 0)
|
||||
return Collections.<TextEvent>emptyList();
|
||||
int x = TokenizerUtils.getLeadingWhiteSpace(seq);
|
||||
int y = TokenizerUtils.getTrailingWhiteSpace(seq);
|
||||
if (x == 0 && y == 0) {
|
||||
TextEvent textEvent = new CharactersEvent(seq);
|
||||
return Collections.<TextEvent>singletonList(textEvent);
|
||||
}
|
||||
if (x == seq.length()) {
|
||||
switch (this.whitespace) {
|
||||
case COMPARE:
|
||||
return Collections.<TextEvent>singletonList(SpaceEvent.getInstance(seq.toString()));
|
||||
case PRESERVE:
|
||||
return Collections.<TextEvent>singletonList(new IgnorableSpaceEvent(seq.toString()));
|
||||
case IGNORE:
|
||||
return Collections.<TextEvent>emptyList();
|
||||
}
|
||||
TextEvent textEvent = new CharactersEvent(seq);
|
||||
return Collections.<TextEvent>singletonList(textEvent);
|
||||
}
|
||||
List<TextEvent> events = null;
|
||||
switch (this.whitespace) {
|
||||
case COMPARE:
|
||||
events = new ArrayList<TextEvent>(1 + ((x > 0) ? 1 : 0) + ((y > 0) ? 1 : 0));
|
||||
if (x > 0)
|
||||
events.add(SpaceEvent.getInstance(seq.subSequence(0, x)));
|
||||
events.add(new CharactersEvent(seq.subSequence(x, seq.length() - y)));
|
||||
if (y > 0)
|
||||
events.add(SpaceEvent.getInstance(seq.subSequence(seq.length() - y, seq.length())));
|
||||
break;
|
||||
case PRESERVE:
|
||||
events = new ArrayList<TextEvent>(1 + ((x > 0) ? 1 : 0) + ((y > 0) ? 1 : 0));
|
||||
if (x > 0)
|
||||
events.add(new IgnorableSpaceEvent(seq.subSequence(0, x)));
|
||||
events.add(new CharactersEvent(seq.subSequence(x, seq.length() - y)));
|
||||
if (y > 0)
|
||||
events.add(new IgnorableSpaceEvent(seq.subSequence(seq.length() - y, seq.length())));
|
||||
break;
|
||||
case IGNORE:
|
||||
e = new CharactersEvent(seq.subSequence(x, seq.length() - y));
|
||||
events = Collections.<TextEvent>singletonList(e);
|
||||
break;
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
public TextGranularity granurality() {
|
||||
return TextGranularity.TEXT;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package com.topologi.diffx.load.text;
|
||||
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
import com.topologi.diffx.config.WhiteSpaceProcessing;
|
||||
import com.topologi.diffx.event.TextEvent;
|
||||
import com.topologi.diffx.event.impl.IgnorableSpaceEvent;
|
||||
import com.topologi.diffx.event.impl.SpaceEvent;
|
||||
import com.topologi.diffx.event.impl.WordEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class TokenizerByWord implements TextTokenizer {
|
||||
private final Map<String, TextEvent> recycling = new HashMap<String, TextEvent>();
|
||||
|
||||
private final WhiteSpaceProcessing whitespace;
|
||||
|
||||
public TokenizerByWord(WhiteSpaceProcessing whitespace) {
|
||||
if (whitespace == null)
|
||||
throw new NullPointerException("the white space processing must be specified.");
|
||||
this.whitespace = whitespace;
|
||||
}
|
||||
|
||||
public List<TextEvent> tokenize(CharSequence seq) {
|
||||
if (seq == null)
|
||||
return null;
|
||||
if (seq.length() == 0)
|
||||
return Collections.<TextEvent>emptyList();
|
||||
List<TextEvent> events = new ArrayList<TextEvent>(seq.length());
|
||||
Pattern p = Pattern.compile("\\s+");
|
||||
Matcher m = p.matcher(seq);
|
||||
int index = 0;
|
||||
while (m.find()) {
|
||||
if (index != m.start()) {
|
||||
String word = seq.subSequence(index, m.start()).toString();
|
||||
events.add(getWordEvent(word));
|
||||
}
|
||||
if (this.whitespace != WhiteSpaceProcessing.IGNORE) {
|
||||
String space = seq.subSequence(m.start(), m.end()).toString();
|
||||
events.add(getSpaceEvent(space));
|
||||
}
|
||||
index = m.end();
|
||||
}
|
||||
if (index != seq.length()) {
|
||||
String word = seq.subSequence(index, seq.length()).toString();
|
||||
events.add(getWordEvent(word));
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
public TextGranularity granurality() {
|
||||
return TextGranularity.WORD;
|
||||
}
|
||||
|
||||
private TextEvent getWordEvent(String word) {
|
||||
TextEvent e = this.recycling.get(word);
|
||||
if (e == null) {
|
||||
e = new WordEvent(word);
|
||||
this.recycling.put(word, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
private TextEvent getSpaceEvent(String space) {
|
||||
TextEvent e = this.recycling.get(space);
|
||||
if (e == null) {
|
||||
if (this.whitespace == WhiteSpaceProcessing.PRESERVE) {
|
||||
e = new IgnorableSpaceEvent(space);
|
||||
} else {
|
||||
e = SpaceEvent.getInstance(space);
|
||||
}
|
||||
this.recycling.put(space, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.topologi.diffx.load.text;
|
||||
|
||||
import com.topologi.diffx.config.DiffXConfig;
|
||||
import com.topologi.diffx.config.TextGranularity;
|
||||
|
||||
public final class TokenizerFactory {
|
||||
public static TextTokenizer get(DiffXConfig config) {
|
||||
if (config == null)
|
||||
throw new NullPointerException("The config should be specified");
|
||||
TextGranularity granularity = config.getGranularity();
|
||||
switch (granularity) {
|
||||
case CHARACTER:
|
||||
return new TokenizerByChar();
|
||||
case WORD:
|
||||
return new TokenizerByWord(config.getWhiteSpaceProcessing());
|
||||
case TEXT:
|
||||
return new TokenizerByText(config.getWhiteSpaceProcessing());
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported text granularity " + granularity);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.topologi.diffx.load.text;
|
||||
|
||||
final class TokenizerUtils {
|
||||
public static int getLeadingWhiteSpace(CharSequence s) {
|
||||
int i = 0;
|
||||
if (0 == s.length())
|
||||
return 0;
|
||||
char c = s.charAt(0);
|
||||
i++;
|
||||
while ((c == ' ' || c == '\t' || c == '\n') && i != s.length())
|
||||
c = s.charAt(i);
|
||||
return i;
|
||||
}
|
||||
|
||||
public static int getTrailingWhiteSpace(CharSequence s) {
|
||||
int i = 0;
|
||||
if (s.length() == 0)
|
||||
return 0;
|
||||
char c = s.charAt(s.length() - 1 - i);
|
||||
i++;
|
||||
while ((c == ' ' || c == '\t' || c == '\n') && i != s.length())
|
||||
c = s.charAt(s.length() - 1 - i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
package com.topologi.diffx.sequence;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public final class EventSequence {
|
||||
private final PrefixMapping prefixMapping = new PrefixMapping();
|
||||
|
||||
private final List<DiffXEvent> sequence;
|
||||
|
||||
public EventSequence() {
|
||||
this.sequence = new LinkedList<DiffXEvent>();
|
||||
}
|
||||
|
||||
public EventSequence(int size) {
|
||||
this.sequence = new ArrayList<DiffXEvent>(size);
|
||||
}
|
||||
|
||||
public void addSequence(EventSequence seq) {
|
||||
for (int i = 0; i < seq.size(); i++)
|
||||
this.sequence.add(seq.getEvent(i));
|
||||
}
|
||||
|
||||
public void addEvent(DiffXEvent e) {
|
||||
this.sequence.add(e);
|
||||
}
|
||||
|
||||
public void addEvent(int i, DiffXEvent e) {
|
||||
this.sequence.add(i, e);
|
||||
}
|
||||
|
||||
public DiffXEvent getEvent(int i) {
|
||||
return this.sequence.get(i);
|
||||
}
|
||||
|
||||
public DiffXEvent setEvent(int index, DiffXEvent e) {
|
||||
return this.sequence.set(index, e);
|
||||
}
|
||||
|
||||
public DiffXEvent removeEvent(int index) {
|
||||
return (DiffXEvent)this.sequence.remove(index);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.sequence.size();
|
||||
}
|
||||
|
||||
public EventIterator eventIterator() {
|
||||
return new EventIterator(this.sequence.iterator());
|
||||
}
|
||||
|
||||
public List<DiffXEvent> events() {
|
||||
return this.sequence;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.sequence.size();
|
||||
}
|
||||
|
||||
public boolean equals(EventSequence seq) {
|
||||
if (seq == null)
|
||||
return false;
|
||||
if (seq.getClass() != getClass())
|
||||
return false;
|
||||
List<DiffXEvent> sequence2 = seq.sequence;
|
||||
if (this.sequence.size() != this.sequence.size())
|
||||
return false;
|
||||
DiffXEvent x1 = null;
|
||||
DiffXEvent x2 = null;
|
||||
for (int i = 0; i < this.sequence.size(); i++) {
|
||||
x1 = this.sequence.get(i);
|
||||
x2 = sequence2.get(i);
|
||||
if (!x1.equals(x2))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof EventSequence))
|
||||
return false;
|
||||
return equals((EventSequence)o);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Event Sequence [" + size() + "]";
|
||||
}
|
||||
|
||||
public void export(PrintWriter w) {
|
||||
DiffXEvent x = null;
|
||||
for (int i = 0; i < this.sequence.size(); i++) {
|
||||
x = this.sequence.get(i);
|
||||
w.println(x.toString());
|
||||
}
|
||||
w.flush();
|
||||
}
|
||||
|
||||
public void mapPrefix(String uri, String prefix) throws NullPointerException {
|
||||
this.prefixMapping.add(uri, prefix);
|
||||
}
|
||||
|
||||
public PrefixMapping getPrefixMapping() {
|
||||
return this.prefixMapping;
|
||||
}
|
||||
|
||||
public final class EventIterator implements Iterator<DiffXEvent> {
|
||||
private final Iterator<DiffXEvent> iterator;
|
||||
|
||||
private EventIterator(Iterator<DiffXEvent> iterator) {
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return this.iterator.hasNext();
|
||||
}
|
||||
|
||||
public DiffXEvent next() {
|
||||
return this.iterator.next();
|
||||
}
|
||||
|
||||
public DiffXEvent nextEvent() throws NoSuchElementException {
|
||||
return this.iterator.next();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
this.iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.topologi.diffx.sequence;
|
||||
|
||||
import com.topologi.diffx.event.CloseElementEvent;
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.event.OpenElementEvent;
|
||||
import java.util.Stack;
|
||||
|
||||
public final class EventSequenceUtils {
|
||||
public static boolean isWellFormed(EventSequence sequence) {
|
||||
if (sequence == null)
|
||||
return false;
|
||||
Stack<DiffXEvent> open = new Stack<DiffXEvent>();
|
||||
DiffXEvent e = null;
|
||||
for (int i = 0; i < sequence.size(); i++) {
|
||||
e = sequence.getEvent(i);
|
||||
if (e instanceof OpenElementEvent) {
|
||||
open.push(e);
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
if (open.empty())
|
||||
return false;
|
||||
OpenElementEvent o = (OpenElementEvent)open.peek();
|
||||
String lastOpenElementName = o.getName();
|
||||
String closeElementName = ((CloseElementEvent)e).getName();
|
||||
if (!closeElementName.equals(lastOpenElementName))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return open.empty();
|
||||
}
|
||||
|
||||
public static int getMaxDepth(EventSequence sequence) {
|
||||
int max = 0;
|
||||
int depth = 0;
|
||||
for (int i = 0; i < sequence.size(); i++) {
|
||||
if (sequence.getEvent(i) instanceof OpenElementEvent) {
|
||||
depth++;
|
||||
} else if (sequence.getEvent(i) instanceof CloseElementEvent) {
|
||||
depth--;
|
||||
}
|
||||
if (depth > max)
|
||||
max = depth;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
public static int getMaxElementContent(EventSequence sequence) {
|
||||
int max = 0;
|
||||
int tmp = 0;
|
||||
for (int i = 0; i < sequence.size(); i++) {
|
||||
DiffXEvent e = sequence.getEvent(i);
|
||||
if (e instanceof OpenElementEvent) {
|
||||
tmp = 0;
|
||||
} else if (e instanceof CloseElementEvent) {
|
||||
if (tmp > max)
|
||||
max = tmp;
|
||||
} else {
|
||||
tmp++;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
package com.topologi.diffx.sequence;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
||||
public final class NaiveSequenceSlicer {
|
||||
final EventSequence sequence1;
|
||||
|
||||
final EventSequence sequence2;
|
||||
|
||||
EventSequence start;
|
||||
|
||||
EventSequence end;
|
||||
|
||||
public NaiveSequenceSlicer(EventSequence seq0, EventSequence seq1) {
|
||||
this.sequence1 = seq0;
|
||||
this.sequence2 = seq1;
|
||||
}
|
||||
|
||||
public int sliceStart() throws IllegalStateException {
|
||||
if (this.start != null)
|
||||
throw new IllegalStateException("The start buffer already contains a subsequence.");
|
||||
this.start = new EventSequence();
|
||||
int count = 0;
|
||||
Iterator<DiffXEvent> i = this.sequence1.eventIterator();
|
||||
Iterator<DiffXEvent> j = this.sequence2.eventIterator();
|
||||
while (i.hasNext() && j.hasNext()) {
|
||||
DiffXEvent e = i.next();
|
||||
if (j.next().equals(e)) {
|
||||
count++;
|
||||
i.remove();
|
||||
j.remove();
|
||||
this.start.addEvent(e);
|
||||
continue;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public int sliceEnd() throws IllegalStateException {
|
||||
if (this.end != null)
|
||||
throw new IllegalStateException("The end buffer already contains a subsequence.");
|
||||
this.end = new EventSequence();
|
||||
int count = 0;
|
||||
int pos1 = this.sequence1.size() - 1;
|
||||
int pos2 = this.sequence2.size() - 1;
|
||||
while (pos1 >= 0 && pos2 >= 0) {
|
||||
DiffXEvent e1 = this.sequence1.getEvent(pos1);
|
||||
if (e1.equals(this.sequence2.getEvent(pos2))) {
|
||||
count++;
|
||||
this.sequence1.removeEvent(pos1--);
|
||||
this.sequence2.removeEvent(pos2--);
|
||||
this.end.addEvent(0, e1);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public int sliceStart(DiffXFormatter formatter) throws IllegalStateException, NullPointerException, IOException {
|
||||
if (this.start != null)
|
||||
throw new IllegalStateException("The start buffer already contains a subsequence.");
|
||||
int count = 0;
|
||||
Iterator<DiffXEvent> i = this.sequence1.eventIterator();
|
||||
Iterator<DiffXEvent> j = this.sequence2.eventIterator();
|
||||
while (i.hasNext() && j.hasNext()) {
|
||||
DiffXEvent e = i.next();
|
||||
if (j.next().equals(e)) {
|
||||
count++;
|
||||
i.remove();
|
||||
j.remove();
|
||||
formatter.format(e);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public int sliceEnd(DiffXFormatter formatter) throws IllegalStateException, NullPointerException, IOException {
|
||||
int count = sliceEnd();
|
||||
formatEnd(formatter);
|
||||
return count;
|
||||
}
|
||||
|
||||
public void formatStart(DiffXFormatter formatter) throws NullPointerException, IOException {
|
||||
if (this.start == null)
|
||||
return;
|
||||
for (int i = 0; i < this.start.size(); i++)
|
||||
formatter.format(this.start.getEvent(i));
|
||||
this.start = null;
|
||||
}
|
||||
|
||||
public void formatEnd(DiffXFormatter formatter) throws NullPointerException, IOException {
|
||||
if (this.end == null)
|
||||
return;
|
||||
for (int i = 0; i < this.end.size(); i++)
|
||||
formatter.format(this.end.getEvent(i));
|
||||
this.end = null;
|
||||
}
|
||||
|
||||
public EventSequence getStart() {
|
||||
return this.start;
|
||||
}
|
||||
|
||||
public EventSequence getEnd() {
|
||||
return this.end;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.topologi.diffx.sequence;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class PrefixMapping {
|
||||
private final Map<String, String> mappings = new HashMap<String, String>();
|
||||
|
||||
public void add(String uri, String prefix) throws NullPointerException {
|
||||
if (!this.mappings.containsKey(uri)) {
|
||||
int count = 0;
|
||||
String actualPrefix = prefix;
|
||||
while (this.mappings.containsValue(actualPrefix))
|
||||
actualPrefix = prefix + count++;
|
||||
this.mappings.put(uri, actualPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
public Enumeration<String> getURIs() {
|
||||
return Collections.<String>enumeration(this.mappings.keySet());
|
||||
}
|
||||
|
||||
public String getPrefix(String uri) {
|
||||
return (uri == null) ? "" : this.mappings.get(uri);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
package com.topologi.diffx.sequence;
|
||||
|
||||
import com.topologi.diffx.event.DiffXEvent;
|
||||
import com.topologi.diffx.format.DiffXFormatter;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
||||
public final class SequenceSlicer {
|
||||
final EventSequence sequence1;
|
||||
|
||||
final EventSequence sequence2;
|
||||
|
||||
EventSequence start;
|
||||
|
||||
EventSequence end;
|
||||
|
||||
public SequenceSlicer(EventSequence seq0, EventSequence seq1) {
|
||||
this.sequence1 = seq0;
|
||||
this.sequence2 = seq1;
|
||||
}
|
||||
|
||||
public void slice() throws IllegalStateException {
|
||||
sliceStart();
|
||||
sliceEnd();
|
||||
}
|
||||
|
||||
public int sliceStart() throws IllegalStateException {
|
||||
if (this.start != null)
|
||||
throw new IllegalStateException("The start buffer already contains a subsequence.");
|
||||
this.start = new EventSequence();
|
||||
int toBeRemoved = 0;
|
||||
int depth = 0;
|
||||
Iterator<DiffXEvent> i = this.sequence1.eventIterator();
|
||||
Iterator<DiffXEvent> j = this.sequence2.eventIterator();
|
||||
int counter = 0;
|
||||
while (i.hasNext() && j.hasNext()) {
|
||||
DiffXEvent e = i.next();
|
||||
if (j.next().equals(e)) {
|
||||
counter++;
|
||||
if (e instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
depth++;
|
||||
} else if (e instanceof com.topologi.diffx.event.CloseElementEvent) {
|
||||
depth--;
|
||||
}
|
||||
if (depth == 1 || depth == 0)
|
||||
toBeRemoved = counter;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (int k = 0; k < toBeRemoved; k++) {
|
||||
DiffXEvent e = this.sequence1.removeEvent(0);
|
||||
this.sequence2.removeEvent(0);
|
||||
this.start.addEvent(e);
|
||||
}
|
||||
return toBeRemoved;
|
||||
}
|
||||
|
||||
public int sliceEnd() throws IllegalStateException {
|
||||
if (this.end != null)
|
||||
throw new IllegalStateException("The end buffer already contains a subsequence.");
|
||||
this.end = new EventSequence();
|
||||
int depth = 0;
|
||||
int toBeRemoved = 0;
|
||||
int counter = 0;
|
||||
int pos1 = this.sequence1.size() - 1;
|
||||
int pos2 = this.sequence2.size() - 1;
|
||||
while (pos1 >= 0 && pos2 >= 0) {
|
||||
DiffXEvent e1 = this.sequence1.getEvent(pos1);
|
||||
if (e1.equals(this.sequence2.getEvent(pos2))) {
|
||||
counter++;
|
||||
if (e1 instanceof com.topologi.diffx.event.CloseElementEvent) {
|
||||
depth++;
|
||||
} else if (e1 instanceof com.topologi.diffx.event.OpenElementEvent) {
|
||||
depth--;
|
||||
}
|
||||
if (depth == 1 || depth == 0)
|
||||
toBeRemoved = counter;
|
||||
pos1--;
|
||||
pos2--;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
int downTo = this.sequence1.size() - toBeRemoved;
|
||||
for (int i = this.sequence1.size() - 1; i >= downTo; i--) {
|
||||
DiffXEvent e = this.sequence1.removeEvent(i);
|
||||
this.end.addEvent(0, e);
|
||||
}
|
||||
downTo = this.sequence2.size() - toBeRemoved;
|
||||
for (int k = this.sequence2.size() - 1; k >= downTo; k--)
|
||||
this.sequence2.removeEvent(k);
|
||||
return toBeRemoved;
|
||||
}
|
||||
|
||||
public void formatStart(DiffXFormatter formatter) throws NullPointerException, IOException {
|
||||
if (this.start == null)
|
||||
return;
|
||||
for (int i = 0; i < this.start.size(); i++)
|
||||
formatter.format(this.start.getEvent(i));
|
||||
this.start = null;
|
||||
}
|
||||
|
||||
public void formatEnd(DiffXFormatter formatter) throws NullPointerException, IOException {
|
||||
if (this.end == null)
|
||||
return;
|
||||
for (int i = 0; i < this.end.size(); i++)
|
||||
formatter.format(this.end.getEvent(i));
|
||||
this.end = null;
|
||||
}
|
||||
|
||||
public EventSequence getStart() {
|
||||
return this.start;
|
||||
}
|
||||
|
||||
public EventSequence getEnd() {
|
||||
return this.end;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.topologi.diffx.util;
|
||||
|
||||
public final class CommandLine {
|
||||
public static String getParameter(String name, String[] args) {
|
||||
if (args == null || args.length < 2 || name == null)
|
||||
return null;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (name.equals(args[i]) && i + 1 < args.length)
|
||||
return args[i + 1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean hasSwitch(String name, String[] args) {
|
||||
if (args == null || name == null)
|
||||
return false;
|
||||
for (String arg : args) {
|
||||
if (name.equals(arg))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.topologi.diffx.util;
|
||||
|
||||
public final class Constants {
|
||||
public static final String BASE_NS_URI = "http://www.topologi.com/2005/Diff-X";
|
||||
|
||||
public static final String DELETE_NS_URI = "http://www.topologi.com/2005/Diff-X/Delete";
|
||||
|
||||
public static final String INSERT_NS_URI = "http://www.topologi.com/2005/Diff-X/Insert";
|
||||
|
||||
@Deprecated
|
||||
public static final String DEFAULT_URI = "";
|
||||
|
||||
@Deprecated
|
||||
public static final String XML_NS_PREFIX = "xml";
|
||||
|
||||
@Deprecated
|
||||
public static final String XML_NS_URI = "http://www.w3.org/XML/1998/namespace";
|
||||
|
||||
@Deprecated
|
||||
public static final String XMLNS_ATTRIBUTE_NS_URI = "http://www.w3.org/2000/xmlns/";
|
||||
|
||||
@Deprecated
|
||||
public static final String XMLNS_ATTRIBUTE = "xmlns";
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.topologi.diffx.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
|
||||
public final class XMLFilenameFilter implements FileFilter {
|
||||
public static final String DEFAULT_EXTENSION = "xml";
|
||||
|
||||
@Deprecated
|
||||
public final String ext = "xml";
|
||||
|
||||
public final boolean ignoreCase;
|
||||
|
||||
public XMLFilenameFilter() {
|
||||
this.ignoreCase = false;
|
||||
}
|
||||
|
||||
public XMLFilenameFilter(boolean ignoreCase) {
|
||||
this.ignoreCase = ignoreCase;
|
||||
}
|
||||
|
||||
public boolean accept(File pathname) throws NullPointerException {
|
||||
if (pathname == null)
|
||||
throw new NullPointerException("The specified file is null.");
|
||||
String name = pathname.getName();
|
||||
int dot = name.lastIndexOf('.');
|
||||
if (dot == -1)
|
||||
return false;
|
||||
String local = name.substring(dot + 1);
|
||||
return this.ignoreCase ? "xml".equalsIgnoreCase(local) : "xml".equals(local);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
public final class IllegalCloseElementException extends IllegalStateException {
|
||||
static final long serialVersionUID = 7264175736386596167L;
|
||||
|
||||
public IllegalCloseElementException() {
|
||||
super("Attempting to close an element with no more element to close.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
public final class UnclosedElementException extends IllegalStateException {
|
||||
static final long serialVersionUID = -186657976801720211L;
|
||||
|
||||
public UnclosedElementException(String name) {
|
||||
super("Attempting to close the XML Writer while element " + name + " has not been closed.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
public final class UndeclaredNamespaceException extends RuntimeException {
|
||||
static final long serialVersionUID = 8080581405972912943L;
|
||||
|
||||
public UndeclaredNamespaceException(String uri) {
|
||||
super("The namespace URI \"" + uri + "\" has not been mapped to any prefix.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
public interface XMLFormattable {
|
||||
StringBuffer toXML(StringBuffer paramStringBuffer) throws NullPointerException;
|
||||
|
||||
String toXML();
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
public final class XMLHelper {
|
||||
public static XMLReader makeXMLReader(ContentHandler handler) throws SAXException, ParserConfigurationException {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(false);
|
||||
factory.setValidating(false);
|
||||
XMLReader reader = factory.newSAXParser().getXMLReader();
|
||||
if (handler != null)
|
||||
reader.setContentHandler(handler);
|
||||
return reader;
|
||||
}
|
||||
|
||||
public static void parse(XMLReader xmlreader, File file) throws FileNotFoundException, SAXException, IOException {
|
||||
InputStream bin = new BufferedInputStream(new FileInputStream(file));
|
||||
Reader reader = new InputStreamReader(bin, "utf-8");
|
||||
InputSource source = new InputSource(reader);
|
||||
xmlreader.parse(source);
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Stack;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
public final class XMLIndenter extends DefaultHandler implements ContentHandler {
|
||||
private final PrintWriter writer;
|
||||
|
||||
private transient int indentLevel = 0;
|
||||
|
||||
private transient Stack<Integer> states = new Stack<Integer>();
|
||||
|
||||
private static final Integer EMPTY = new Integer(0);
|
||||
|
||||
private static final Integer HAS_TEXT = new Integer(1);
|
||||
|
||||
private static final Integer HAS_CHILDREN = new Integer(2);
|
||||
|
||||
private XMLIndenter(Writer w) {
|
||||
if (w instanceof PrintWriter) {
|
||||
this.writer = (PrintWriter)w;
|
||||
} else {
|
||||
this.writer = new PrintWriter(w);
|
||||
}
|
||||
}
|
||||
|
||||
public void startElement(String uri, String localName, String qName, Attributes atts) {
|
||||
if (!this.states.empty()) {
|
||||
if (this.states.pop().equals(EMPTY))
|
||||
this.writer.println('>');
|
||||
this.states.push(HAS_CHILDREN);
|
||||
}
|
||||
for (int j = 0; j < this.indentLevel; j++)
|
||||
this.writer.print(" ");
|
||||
this.writer.print('<' + qName);
|
||||
for (int i = 0; i < atts.getLength(); i++)
|
||||
this.writer.print(' ' + atts.getQName(i) + "=\"" + atts.getValue(i) + '"');
|
||||
this.indentLevel++;
|
||||
this.states.push(EMPTY);
|
||||
}
|
||||
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
this.indentLevel--;
|
||||
Object state = this.states.pop();
|
||||
if (EMPTY.equals(state)) {
|
||||
this.writer.println("/>");
|
||||
} else if (HAS_TEXT.equals(state)) {
|
||||
this.writer.println("</" + qName + '>');
|
||||
} else if (HAS_CHILDREN.equals(state)) {
|
||||
for (int i = 0; i < this.indentLevel; i++)
|
||||
this.writer.print(" ");
|
||||
this.writer.println("</" + qName + '>');
|
||||
}
|
||||
}
|
||||
|
||||
public void characters(char[] ch, int position, int offset) {
|
||||
if (this.states.peek().equals(EMPTY)) {
|
||||
this.states.pop();
|
||||
this.writer.print('>');
|
||||
this.states.push(HAS_TEXT);
|
||||
}
|
||||
this.writer.print(new String(ch, position, offset));
|
||||
}
|
||||
|
||||
public void ignorableWhitespace(char[] ch, int position, int offset) {}
|
||||
|
||||
public static String indent(String xml) throws SAXException, IOException, ParserConfigurationException {
|
||||
Writer writer = new StringWriter();
|
||||
Reader reader = new StringReader(xml);
|
||||
indent(reader, writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
public static void indent(Reader r, Writer w) throws SAXException, IOException, ParserConfigurationException {
|
||||
XMLIndenter indenter = new XMLIndenter(w);
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(false);
|
||||
factory.setValidating(false);
|
||||
InputSource source = new InputSource(r);
|
||||
XMLReader xmlreader = factory.newSAXParser().getXMLReader();
|
||||
xmlreader.setContentHandler(indenter);
|
||||
xmlreader.parse(source);
|
||||
}
|
||||
|
||||
public static String indentSilent(String xml) {
|
||||
try {
|
||||
return indent(xml);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean indentSilent(Reader r, Writer w) {
|
||||
try {
|
||||
indent(r, w);
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
public interface XMLSerializable {}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public final class XMLSerializer {
|
||||
private static final DateFormat DF = new SimpleDateFormat("dd/MM/yyyy");
|
||||
|
||||
private final XMLWriter xml;
|
||||
|
||||
public XMLSerializer(XMLWriter xml) {
|
||||
this.xml = xml;
|
||||
}
|
||||
|
||||
public XMLWriter getXML() {
|
||||
return this.xml;
|
||||
}
|
||||
|
||||
public void serialize(Object o, String name) throws IOException {
|
||||
if (o != null) {
|
||||
if (name.lastIndexOf('.') != -1)
|
||||
name = name.substring(name.lastIndexOf('.') + 1);
|
||||
if (name.lastIndexOf('$') != -1)
|
||||
name = name.substring(name.lastIndexOf('$') + 1);
|
||||
name = name.toLowerCase();
|
||||
if (o instanceof Number) {
|
||||
this.xml.openElement(name, false);
|
||||
this.xml.writeText(o.toString());
|
||||
this.xml.closeElement();
|
||||
} else if (o instanceof String) {
|
||||
this.xml.openElement(name, false);
|
||||
this.xml.writeText(o.toString());
|
||||
this.xml.closeElement();
|
||||
} else if (o instanceof Character) {
|
||||
this.xml.openElement(name, false);
|
||||
this.xml.writeText(((Character)o).charValue());
|
||||
this.xml.closeElement();
|
||||
} else if (o instanceof Boolean) {
|
||||
this.xml.openElement(name, false);
|
||||
this.xml.writeText(o.toString());
|
||||
this.xml.closeElement();
|
||||
} else if (o instanceof Date) {
|
||||
this.xml.openElement(name, false);
|
||||
this.xml.writeText(DF.format((Date)o));
|
||||
this.xml.closeElement();
|
||||
} else if (o instanceof Collection) {
|
||||
this.xml.openElement(name, (((Collection)o).size() != 0));
|
||||
serializeCollection((Collection)o);
|
||||
this.xml.closeElement();
|
||||
} else if (o instanceof Hashtable) {
|
||||
this.xml.openElement(name, (((Hashtable)o).size() != 0));
|
||||
serializeHashtable((Hashtable<?, ?>)o);
|
||||
this.xml.closeElement();
|
||||
} else {
|
||||
this.xml.openElement(name, true);
|
||||
serializeObject(o);
|
||||
this.xml.closeElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void serializeCollection(Collection<?> c) throws IOException {
|
||||
for (Object o : (Iterable<Object>)c)
|
||||
serialize(o, o.getClass().getName());
|
||||
}
|
||||
|
||||
public void serializeHashtable(Hashtable<?, ?> h) throws IOException {
|
||||
this.xml.openElement("map", !h.isEmpty());
|
||||
for (Enumeration<?> e = h.keys(); e.hasMoreElements(); ) {
|
||||
Object key = e.nextElement();
|
||||
Object value = h.get(key);
|
||||
this.xml.openElement("element");
|
||||
this.xml.openElement("key");
|
||||
serialize(key, "key");
|
||||
this.xml.closeElement();
|
||||
this.xml.openElement("value");
|
||||
serialize(value, "value");
|
||||
this.xml.closeElement();
|
||||
this.xml.closeElement();
|
||||
}
|
||||
this.xml.closeElement();
|
||||
}
|
||||
|
||||
public void serializeObject(Object o) throws IOException {
|
||||
if (o instanceof XMLSerializable) {
|
||||
try {
|
||||
Object[] args = new Object[0];
|
||||
Class<?> cls = o.getClass();
|
||||
Method[] meth = cls.getMethods();
|
||||
for (Method element : meth) {
|
||||
String methodName = element.getName();
|
||||
if (methodName.startsWith("get") && !"getClass".equals(methodName)) {
|
||||
Object retObj = element.invoke(o, args);
|
||||
String attribute = methodName.substring(3).toLowerCase();
|
||||
serialize(retObj, attribute);
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException ex) {
|
||||
ex.printStackTrace();
|
||||
} catch (InvocationTargetException ex) {
|
||||
ex.getTargetException().printStackTrace();
|
||||
}
|
||||
} else if (o instanceof XMLWritable) {
|
||||
((XMLWritable)o).toXML(this.xml);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
|
||||
public final class XMLStringWriter implements XMLWriter {
|
||||
private final StringWriter writer;
|
||||
|
||||
private final XMLWriter xml;
|
||||
|
||||
public XMLStringWriter(boolean namespaces) {
|
||||
this(namespaces, false);
|
||||
}
|
||||
|
||||
public XMLStringWriter(boolean namespaces, boolean indent) {
|
||||
this.writer = new StringWriter();
|
||||
this.xml = namespaces ? new XMLWriterNSImpl(this.writer, indent) : new XMLWriterImpl(this.writer, indent);
|
||||
}
|
||||
|
||||
public void xmlDecl() {
|
||||
try {
|
||||
this.xml.xmlDecl();
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void setIndentChars(String spaces) {
|
||||
this.xml.setIndentChars(spaces);
|
||||
}
|
||||
|
||||
public void writeText(char c) {
|
||||
try {
|
||||
this.xml.writeText(c);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeText(String text) {
|
||||
try {
|
||||
this.xml.writeText(text);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeText(char[] text, int off, int len) {
|
||||
try {
|
||||
this.xml.writeText(text, off, len);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeCDATA(String cdata) {
|
||||
try {
|
||||
this.xml.writeCDATA(cdata);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeXML(String text) {
|
||||
try {
|
||||
this.xml.writeXML(text);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeXML(char[] text, int off, int len) {
|
||||
try {
|
||||
this.xml.writeXML(text, off, len);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeComment(String comment) {
|
||||
try {
|
||||
this.xml.writeComment(comment);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void writePI(String target, String data) {
|
||||
try {
|
||||
this.xml.writePI(target, data);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void openElement(String name) {
|
||||
try {
|
||||
this.xml.openElement(name);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void openElement(String name, boolean hasChildren) {
|
||||
try {
|
||||
this.xml.openElement(name, hasChildren);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name, boolean hasChildren) {
|
||||
try {
|
||||
this.xml.openElement(uri, name, hasChildren);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void closeElement() {
|
||||
try {
|
||||
this.xml.closeElement();
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void element(String name, String text) {
|
||||
try {
|
||||
this.xml.element(name, text);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void emptyElement(String element) {
|
||||
try {
|
||||
this.xml.emptyElement(element);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void emptyElement(String uri, String element) {
|
||||
try {
|
||||
this.xml.emptyElement(element);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void attribute(String name, String value) {
|
||||
try {
|
||||
this.xml.attribute(name, value);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void attribute(String name, int value) {
|
||||
try {
|
||||
this.xml.attribute(name, value);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, String value) {
|
||||
try {
|
||||
this.xml.attribute(uri, name, value);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, int value) {
|
||||
try {
|
||||
this.xml.attribute(uri, name, value);
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void setPrefixMapping(String uri, String prefix) {
|
||||
this.xml.setPrefixMapping(uri, prefix);
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
try {
|
||||
this.xml.flush();
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws UnclosedElementException {
|
||||
try {
|
||||
this.xml.close();
|
||||
} catch (IOException ex) {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.writer.toString();
|
||||
}
|
||||
|
||||
private static void doNothing() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import com.topologi.diffx.xml.esc.XMLEscapeUTF8;
|
||||
|
||||
public final class XMLUtils {
|
||||
public static String escape(String s) {
|
||||
return XMLEscapeUTF8.UTF8_ESCAPE.toElementText(s);
|
||||
}
|
||||
|
||||
public static String escapeAttr(String s) {
|
||||
return XMLEscapeUTF8.UTF8_ESCAPE.toAttributeValue(s);
|
||||
}
|
||||
|
||||
public static String toElementName(String name) {
|
||||
if (name == null)
|
||||
return null;
|
||||
char[] elementAsChars = name.toCharArray();
|
||||
if (!Character.isLetter(elementAsChars[0])) {
|
||||
elementAsChars[0] = 'x';
|
||||
} else {
|
||||
elementAsChars[0] = Character.toLowerCase(elementAsChars[0]);
|
||||
}
|
||||
for (int i = 1; i < elementAsChars.length; i++) {
|
||||
if (!Character.isLetter(elementAsChars[i])) {
|
||||
elementAsChars[i] = '-';
|
||||
} else {
|
||||
elementAsChars[i] = Character.toLowerCase(elementAsChars[i]);
|
||||
}
|
||||
}
|
||||
return new String(elementAsChars);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface XMLWritable {
|
||||
void toXML(XMLWriter paramXMLWriter) throws IOException;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface XMLWriter {
|
||||
void xmlDecl() throws IOException;
|
||||
|
||||
void setIndentChars(String paramString);
|
||||
|
||||
void writeText(char paramChar) throws IOException;
|
||||
|
||||
void writeText(String paramString) throws IOException;
|
||||
|
||||
void writeText(char[] paramArrayOfchar, int paramInt1, int paramInt2) throws IOException;
|
||||
|
||||
void writeCDATA(String paramString) throws IOException;
|
||||
|
||||
void writeXML(String paramString) throws IOException;
|
||||
|
||||
void writeXML(char[] paramArrayOfchar, int paramInt1, int paramInt2) throws IOException;
|
||||
|
||||
void writeComment(String paramString) throws IOException;
|
||||
|
||||
void writePI(String paramString1, String paramString2) throws IOException;
|
||||
|
||||
void openElement(String paramString) throws IOException;
|
||||
|
||||
void openElement(String paramString, boolean paramBoolean) throws IOException;
|
||||
|
||||
void openElement(String paramString1, String paramString2, boolean paramBoolean) throws IOException;
|
||||
|
||||
void closeElement() throws IOException;
|
||||
|
||||
void element(String paramString1, String paramString2) throws IOException;
|
||||
|
||||
void emptyElement(String paramString) throws IOException;
|
||||
|
||||
void emptyElement(String paramString1, String paramString2) throws IOException;
|
||||
|
||||
void attribute(String paramString1, String paramString2) throws IOException;
|
||||
|
||||
void attribute(String paramString, int paramInt) throws IOException;
|
||||
|
||||
void attribute(String paramString1, String paramString2, String paramString3) throws IOException;
|
||||
|
||||
void attribute(String paramString1, String paramString2, int paramInt) throws IOException;
|
||||
|
||||
void setPrefixMapping(String paramString1, String paramString2);
|
||||
|
||||
void flush() throws IOException;
|
||||
|
||||
void close() throws IOException;
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import com.topologi.diffx.xml.esc.XMLEscapeWriter;
|
||||
import com.topologi.diffx.xml.esc.XMLEscapeWriterUTF8;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
abstract class XMLWriterBase implements XMLWriter {
|
||||
final Writer writer;
|
||||
|
||||
String encoding = "utf-8";
|
||||
|
||||
XMLEscapeWriter writerEscape;
|
||||
|
||||
int depth = 0;
|
||||
|
||||
boolean indent;
|
||||
|
||||
private String indentChars = null;
|
||||
|
||||
boolean isNude = false;
|
||||
|
||||
public XMLWriterBase(Writer writer, boolean indent) throws NullPointerException {
|
||||
if (writer == null)
|
||||
throw new NullPointerException("XMLWriter cannot use a null writer.");
|
||||
this.writer = writer;
|
||||
this.writerEscape = new XMLEscapeWriterUTF8(writer);
|
||||
this.indent = indent;
|
||||
if (indent)
|
||||
this.indentChars = " ";
|
||||
}
|
||||
|
||||
public final void xmlDecl() throws IOException {
|
||||
this.writer.write("<?xml version=\"1.0\" encoding=\"" + this.encoding + "\"?>");
|
||||
if (this.indent)
|
||||
this.writer.write(10);
|
||||
}
|
||||
|
||||
public final void setIndentChars(String spaces) throws IllegalStateException, IllegalArgumentException {
|
||||
if (this.depth != 0)
|
||||
throw new IllegalStateException("To late to set the indentation characters!");
|
||||
if (spaces != null)
|
||||
for (int i = 0; i < spaces.length(); i++) {
|
||||
if (!Character.isSpaceChar(spaces.charAt(i)))
|
||||
throw new IllegalArgumentException("Not a valid indentation string.");
|
||||
}
|
||||
this.indentChars = spaces;
|
||||
this.indent = (spaces != null);
|
||||
}
|
||||
|
||||
public final void setEncoding(String encoding) throws IllegalStateException, IllegalArgumentException {
|
||||
if (this.depth != 0)
|
||||
throw new IllegalStateException("To late to set the encoding!");
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
public final void writeText(String text) throws IOException {
|
||||
if (text == null)
|
||||
return;
|
||||
deNude();
|
||||
this.writerEscape.writeText(text);
|
||||
}
|
||||
|
||||
public final void writeText(char[] text, int off, int len) throws IOException {
|
||||
deNude();
|
||||
this.writerEscape.writeText(text, off, len);
|
||||
}
|
||||
|
||||
public final void writeText(char c) throws IOException {
|
||||
deNude();
|
||||
this.writerEscape.writeText(c);
|
||||
}
|
||||
|
||||
public final void writeText(Object o) throws IOException {
|
||||
if (o != null)
|
||||
writeText(o.toString());
|
||||
}
|
||||
|
||||
public final void writeXML(String text) throws IOException {
|
||||
if (text == null)
|
||||
return;
|
||||
deNude();
|
||||
this.writer.write(text);
|
||||
}
|
||||
|
||||
public final void writeXML(char[] text, int off, int len) throws IOException {
|
||||
deNude();
|
||||
this.writer.write(text, off, len);
|
||||
}
|
||||
|
||||
public final void writeComment(String comment) throws IOException, IllegalArgumentException {
|
||||
if (comment == null)
|
||||
return;
|
||||
if (comment.indexOf("--") >= 0)
|
||||
throw new IllegalArgumentException("A comment must not contain '--'.");
|
||||
deNude();
|
||||
this.writer.write("<!-- ");
|
||||
this.writer.write(comment);
|
||||
this.writer.write(" -->");
|
||||
if (this.indent)
|
||||
this.writer.write(10);
|
||||
}
|
||||
|
||||
public final void writePI(String target, String data) throws IOException {
|
||||
deNude();
|
||||
this.writer.write("<?");
|
||||
this.writer.write(target);
|
||||
this.writer.write(32);
|
||||
this.writer.write(data);
|
||||
this.writer.write("?>");
|
||||
if (this.indent)
|
||||
this.writer.write(10);
|
||||
}
|
||||
|
||||
public final void writeCDATA(String data) throws IOException {
|
||||
if (data == null)
|
||||
return;
|
||||
String end = "]]>";
|
||||
if (data.indexOf("]]>") >= 0)
|
||||
throw new IllegalArgumentException("CDATA sections must not contain ']]>'");
|
||||
deNude();
|
||||
this.writer.write("<![CDATA[");
|
||||
this.writer.write(data);
|
||||
this.writer.write("]]>");
|
||||
}
|
||||
|
||||
public final void attribute(String name, String value) throws IOException {
|
||||
if (!this.isNude)
|
||||
throw new IllegalStateException("Cannot write attribute: too late!");
|
||||
this.writer.write(32);
|
||||
this.writer.write(name);
|
||||
this.writer.write(61);
|
||||
this.writer.write(34);
|
||||
this.writerEscape.writeAttValue(value);
|
||||
this.writer.write(34);
|
||||
}
|
||||
|
||||
public final void attribute(String name, int value) throws IOException {
|
||||
if (!this.isNude)
|
||||
throw new IllegalStateException("Cannot write attribute: too late!");
|
||||
this.writer.write(32);
|
||||
this.writer.write(name);
|
||||
this.writer.write(61);
|
||||
this.writer.write(34);
|
||||
this.writer.write(Integer.toString(value));
|
||||
this.writer.write(34);
|
||||
}
|
||||
|
||||
public void element(String name, String text) throws IOException {
|
||||
openElement(name);
|
||||
writeText(text);
|
||||
closeElement();
|
||||
}
|
||||
|
||||
public final void flush() throws IOException {
|
||||
this.writer.flush();
|
||||
}
|
||||
|
||||
abstract void deNude() throws IOException;
|
||||
|
||||
void indent() throws IOException {
|
||||
if (this.indent)
|
||||
for (int i = 0; i < this.depth; i++)
|
||||
this.writer.write(this.indentChars);
|
||||
}
|
||||
|
||||
static final void doNothing() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class XMLWriterImpl extends XMLWriterBase implements XMLWriter {
|
||||
private static final Element ROOT = new Element("", true);
|
||||
|
||||
private final List<Element> elements = new ArrayList<Element>();
|
||||
|
||||
public XMLWriterImpl(Writer writer) throws NullPointerException {
|
||||
super(writer, false);
|
||||
this.elements.add(ROOT);
|
||||
}
|
||||
|
||||
public XMLWriterImpl(Writer writer, boolean indent) throws NullPointerException {
|
||||
super(writer, indent);
|
||||
this.elements.add(ROOT);
|
||||
}
|
||||
|
||||
void deNude() throws IOException {
|
||||
if (this.isNude) {
|
||||
this.writer.write(62);
|
||||
if ((peekElement()).hasChildren && this.indent)
|
||||
this.writer.write(10);
|
||||
this.isNude = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void openElement(String name) throws IOException {
|
||||
openElement(name, false);
|
||||
}
|
||||
|
||||
public void openElement(String name, boolean hasChildren) throws IOException {
|
||||
deNude();
|
||||
indent();
|
||||
this.elements.add(new Element(name, hasChildren));
|
||||
this.writer.write(60);
|
||||
this.writer.write(name);
|
||||
this.isNude = true;
|
||||
this.depth++;
|
||||
}
|
||||
|
||||
public void closeElement() throws IOException, IllegalCloseElementException {
|
||||
Element elt = popElement();
|
||||
if (elt == ROOT)
|
||||
throw new IllegalCloseElementException();
|
||||
this.depth--;
|
||||
if (this.isNude) {
|
||||
this.writer.write(47);
|
||||
this.isNude = false;
|
||||
} else {
|
||||
if (elt.hasChildren)
|
||||
indent();
|
||||
this.writer.write(60);
|
||||
this.writer.write(47);
|
||||
int x = elt.name.indexOf(' ');
|
||||
if (x < 0) {
|
||||
this.writer.write(elt.name);
|
||||
} else {
|
||||
this.writer.write(elt.name.substring(0, x));
|
||||
}
|
||||
}
|
||||
this.writer.write(62);
|
||||
if (this.indent) {
|
||||
Element parent = peekElement();
|
||||
if (parent.hasChildren && parent != ROOT)
|
||||
this.writer.write(10);
|
||||
}
|
||||
}
|
||||
|
||||
public void emptyElement(String element) throws IOException {
|
||||
deNude();
|
||||
indent();
|
||||
this.writer.write(60);
|
||||
this.writer.write(element);
|
||||
this.writer.write(47);
|
||||
this.writer.write(62);
|
||||
if (this.indent) {
|
||||
Element parent = peekElement();
|
||||
if (parent.hasChildren && parent != ROOT)
|
||||
this.writer.write(10);
|
||||
}
|
||||
}
|
||||
|
||||
private Element peekElement() {
|
||||
return this.elements.get(this.elements.size() - 1);
|
||||
}
|
||||
|
||||
private Element popElement() {
|
||||
return (Element)this.elements.remove(this.elements.size() - 1);
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces.");
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name, boolean hasChildren) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces.");
|
||||
}
|
||||
|
||||
public void emptyElement(String uri, String element) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void setPrefixMapping(String uri, String prefix) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, String value) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, int value) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void close() throws IOException, UnclosedElementException {
|
||||
Element open = peekElement();
|
||||
if (open != ROOT)
|
||||
throw new UnclosedElementException(open.name);
|
||||
this.writer.close();
|
||||
}
|
||||
|
||||
private static final class Element {
|
||||
private final String name;
|
||||
|
||||
private final boolean hasChildren;
|
||||
|
||||
public Element(String name, boolean hasChildren) {
|
||||
this.name = name;
|
||||
this.hasChildren = hasChildren;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
package com.topologi.diffx.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class XMLWriterNSImpl extends XMLWriterBase implements XMLWriter {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final PrefixMapping DEFAULT_NS = new PrefixMapping("", "");
|
||||
|
||||
private static final Element ROOT;
|
||||
|
||||
static {
|
||||
List<PrefixMapping> mps = new ArrayList<PrefixMapping>();
|
||||
mps.add(DEFAULT_NS);
|
||||
ROOT = new Element("", true, mps);
|
||||
}
|
||||
|
||||
private final Map<String, String> prefixMapping = new HashMap<String, String>();
|
||||
|
||||
private List<PrefixMapping> tempMapping;
|
||||
|
||||
private final List<Element> elements = new ArrayList<Element>();
|
||||
|
||||
public XMLWriterNSImpl(Writer writer) throws NullPointerException {
|
||||
this(writer, false);
|
||||
}
|
||||
|
||||
public XMLWriterNSImpl(Writer writer, boolean indent) throws NullPointerException {
|
||||
super(writer, indent);
|
||||
this.elements.add(ROOT);
|
||||
this.prefixMapping.put("", "");
|
||||
this.prefixMapping.put("http://www.w3.org/XML/1998/namespace", "xml");
|
||||
}
|
||||
|
||||
void deNude() throws IOException {
|
||||
if (this.isNude) {
|
||||
this.writer.write(62);
|
||||
if (this.indent && (peekElement()).hasChildren)
|
||||
this.writer.write(10);
|
||||
this.isNude = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void openElement(String name) throws IOException {
|
||||
openElement(null, name, false);
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name) throws IOException {
|
||||
openElement(uri, name, false);
|
||||
}
|
||||
|
||||
public void openElement(String name, boolean hasChildren) throws IOException {
|
||||
openElement(null, name, hasChildren);
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name, boolean hasChildren) throws IOException {
|
||||
deNude();
|
||||
indent();
|
||||
String qName = getQName(uri, name);
|
||||
this.elements.add(new Element(qName, hasChildren, this.tempMapping));
|
||||
this.writer.write(60);
|
||||
this.writer.write(qName);
|
||||
handleNamespaceDeclaration();
|
||||
this.isNude = true;
|
||||
this.depth++;
|
||||
}
|
||||
|
||||
public void closeElement() throws IOException {
|
||||
Element elt = popElement();
|
||||
if (elt == ROOT)
|
||||
throw new IllegalCloseElementException();
|
||||
this.depth--;
|
||||
if (this.isNude) {
|
||||
this.writer.write(47);
|
||||
this.isNude = false;
|
||||
} else {
|
||||
if (elt.hasChildren)
|
||||
indent();
|
||||
this.writer.write(60);
|
||||
this.writer.write(47);
|
||||
int x = elt.qName.indexOf(' ');
|
||||
if (x < 0) {
|
||||
this.writer.write(elt.qName);
|
||||
} else {
|
||||
this.writer.write(elt.qName.substring(0, x));
|
||||
}
|
||||
}
|
||||
restorePrefixMapping(elt);
|
||||
this.writer.write(62);
|
||||
if (this.indent) {
|
||||
Element parent = peekElement();
|
||||
if (parent.hasChildren && parent != ROOT)
|
||||
this.writer.write(10);
|
||||
}
|
||||
}
|
||||
|
||||
public void emptyElement(String element) throws IOException {
|
||||
emptyElement(null, element);
|
||||
}
|
||||
|
||||
public void emptyElement(String uri, String element) throws IOException {
|
||||
deNude();
|
||||
indent();
|
||||
this.writer.write(60);
|
||||
this.writer.write(getQName(uri, element));
|
||||
handleNamespaceDeclaration();
|
||||
this.writer.write(47);
|
||||
this.writer.write(62);
|
||||
if (this.indent)
|
||||
this.writer.write(10);
|
||||
}
|
||||
|
||||
private Element peekElement() {
|
||||
return this.elements.get(this.elements.size() - 1);
|
||||
}
|
||||
|
||||
private Element popElement() {
|
||||
return (Element)this.elements.remove(this.elements.size() - 1);
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, String value) throws IOException, IllegalStateException {
|
||||
if (!this.isNude)
|
||||
throw new IllegalArgumentException("Cannot write attribute: too late!");
|
||||
this.writer.write(32);
|
||||
this.writer.write(getQName(uri, name));
|
||||
this.writer.write("=\"");
|
||||
this.writerEscape.writeAttValue(value);
|
||||
this.writer.write(34);
|
||||
handleNamespaceDeclaration();
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, int value) throws IOException, IllegalStateException {
|
||||
if (!this.isNude)
|
||||
throw new IllegalArgumentException("Cannot write attribute: too late!");
|
||||
this.writer.write(32);
|
||||
this.writer.write(getQName(uri, name));
|
||||
this.writer.write("=\"");
|
||||
this.writer.write(Integer.toString(value));
|
||||
this.writer.write(34);
|
||||
handleNamespaceDeclaration();
|
||||
}
|
||||
|
||||
public void setPrefixMapping(String uri, String prefix) throws NullPointerException {
|
||||
if (!prefix.equals(this.prefixMapping.get(uri))) {
|
||||
removeIfNeeded(prefix);
|
||||
PrefixMapping pm = new PrefixMapping(prefix, uri);
|
||||
this.prefixMapping.put(pm.uri, pm.prefix);
|
||||
if (this.tempMapping == null)
|
||||
this.tempMapping = new ArrayList<PrefixMapping>();
|
||||
this.tempMapping.add(pm);
|
||||
}
|
||||
}
|
||||
|
||||
private String getQName(String uri, String name) throws UndeclaredNamespaceException {
|
||||
String prefix = this.prefixMapping.get((uri != null) ? uri : "");
|
||||
if (prefix != null) {
|
||||
if (!"".equals(prefix))
|
||||
return (String)this.prefixMapping.get(uri) + ":" + name;
|
||||
return name;
|
||||
}
|
||||
if (uri == null)
|
||||
return name;
|
||||
throw new UndeclaredNamespaceException(uri);
|
||||
}
|
||||
|
||||
private void handleNamespaceDeclaration() throws IOException {
|
||||
if (this.tempMapping != null) {
|
||||
PrefixMapping pm = null;
|
||||
for (int i = 0; i < this.tempMapping.size(); i++) {
|
||||
pm = this.tempMapping.get(i);
|
||||
if (!"xml".equals(pm.prefix)) {
|
||||
this.writer.write(" xmlns");
|
||||
if (!"".equals(pm.prefix)) {
|
||||
this.writer.write(58);
|
||||
this.writer.write(pm.prefix);
|
||||
}
|
||||
this.writer.write("=\"");
|
||||
this.writer.write(pm.uri);
|
||||
this.writer.write("\"");
|
||||
}
|
||||
}
|
||||
this.tempMapping = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void restorePrefixMapping(Element elt) {
|
||||
if (elt.mappings != null)
|
||||
for (int i = 0; i < elt.mappings.size(); i++) {
|
||||
PrefixMapping mpi = elt.mappings.get(i);
|
||||
for (int j = this.elements.size() - 1; j > 0; j--) {
|
||||
if ((this.elements.get(j)).mappings != null) {
|
||||
List<PrefixMapping> mps = (this.elements.get(j)).mappings;
|
||||
for (int k = 0; k < mps.size(); k++) {
|
||||
PrefixMapping mpk = mps.get(k);
|
||||
if (mpk.prefix.equals(mpi.prefix)) {
|
||||
removeIfNeeded(mpk.prefix);
|
||||
this.prefixMapping.put(mpk.uri, mpk.prefix);
|
||||
j = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeIfNeeded(String prefix) {
|
||||
if (this.prefixMapping.containsValue(prefix)) {
|
||||
Map.Entry<String, String> remove = null;
|
||||
for (Map.Entry<String, String> e : this.prefixMapping.entrySet()) {
|
||||
if (e.getValue().equals(prefix)) {
|
||||
remove = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.prefixMapping.remove(remove.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException, UnclosedElementException {
|
||||
Element open = peekElement();
|
||||
if (open != ROOT)
|
||||
throw new UnclosedElementException(open.qName);
|
||||
this.writer.close();
|
||||
}
|
||||
|
||||
private static final class Element {
|
||||
private final String qName;
|
||||
|
||||
private final boolean hasChildren;
|
||||
|
||||
private final List<XMLWriterNSImpl.PrefixMapping> mappings;
|
||||
|
||||
public Element(String qName, boolean hasChildren, List<XMLWriterNSImpl.PrefixMapping> mappings) {
|
||||
this.qName = qName;
|
||||
this.hasChildren = hasChildren;
|
||||
this.mappings = mappings;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class PrefixMapping {
|
||||
private final String prefix;
|
||||
|
||||
private final String uri;
|
||||
|
||||
public PrefixMapping(String prefix, String uri) {
|
||||
this.prefix = (prefix != null) ? prefix : "";
|
||||
this.uri = (uri != null) ? uri : "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.topologi.diffx.xml.dom;
|
||||
|
||||
import com.topologi.diffx.xml.XMLWriter;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
public interface DOMWriter extends XMLWriter {
|
||||
Document getDocument();
|
||||
}
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
package com.topologi.diffx.xml.dom;
|
||||
|
||||
import com.topologi.diffx.xml.IllegalCloseElementException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.DOMException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
public final class DOMWriterImpl implements DOMWriter {
|
||||
private final Document document;
|
||||
|
||||
private final Node newline;
|
||||
|
||||
private boolean indent;
|
||||
|
||||
private String indentChars;
|
||||
|
||||
private transient int depth;
|
||||
|
||||
private transient boolean isNude;
|
||||
|
||||
private transient Node currentElement;
|
||||
|
||||
private transient List<Boolean> childrenFlags = new ArrayList<Boolean>();
|
||||
|
||||
public DOMWriterImpl() throws ParserConfigurationException {
|
||||
this(newDocument());
|
||||
}
|
||||
|
||||
public DOMWriterImpl(Document document) {
|
||||
if (document == null)
|
||||
throw new NullPointerException("The XMLWriter requires a DOM Document to write on.");
|
||||
this.document = document;
|
||||
this.currentElement = document;
|
||||
this.newline = document.createTextNode("\n");
|
||||
}
|
||||
|
||||
public void xmlDecl() {}
|
||||
|
||||
public void setIndentChars(String spaces) {
|
||||
if (this.depth != 0)
|
||||
throw new IllegalStateException("To late to set the indentation characters!");
|
||||
if (spaces != null)
|
||||
for (int i = 0; i < spaces.length(); i++) {
|
||||
if (!Character.isSpaceChar(spaces.charAt(i)))
|
||||
throw new IllegalArgumentException("Not a valid indentation string.");
|
||||
}
|
||||
this.indentChars = spaces;
|
||||
this.indent = (spaces != null);
|
||||
}
|
||||
|
||||
public void writeText(String text) {
|
||||
if (text == null)
|
||||
return;
|
||||
deNude();
|
||||
Text textNode = this.document.createTextNode(text);
|
||||
this.currentElement.appendChild(textNode);
|
||||
}
|
||||
|
||||
public void writeText(char[] text, int off, int len) {
|
||||
writeText(new String(text, off, len));
|
||||
}
|
||||
|
||||
public void writeText(char c) {
|
||||
writeText(new String(new char[] { c }));
|
||||
}
|
||||
|
||||
public void writeText(Object o) {
|
||||
if (o != null)
|
||||
writeText(o.toString());
|
||||
}
|
||||
|
||||
public void writeCDATA(String data) {
|
||||
if (data == null)
|
||||
return;
|
||||
this.document.createCDATASection(data);
|
||||
}
|
||||
|
||||
public void writeXML(String text) {
|
||||
throw new UnsupportedOperationException("Cannot use unparsed XML as DOM node.");
|
||||
}
|
||||
|
||||
public void writeXML(char[] text, int off, int len) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("Cannot use unparsed XML as DOM node.");
|
||||
}
|
||||
|
||||
public void writeComment(String comment) throws DOMException {
|
||||
if (comment.indexOf("--") >= 0)
|
||||
throw new IllegalArgumentException("A comment must not contain '--'.");
|
||||
deNude();
|
||||
Node node = this.document.createComment(comment);
|
||||
this.currentElement.appendChild(node);
|
||||
if (this.indent)
|
||||
newLine();
|
||||
}
|
||||
|
||||
public void writePI(String target, String data) throws DOMException {
|
||||
deNude();
|
||||
Node node = this.document.createProcessingInstruction(target, data);
|
||||
this.currentElement.appendChild(node);
|
||||
if (this.indent)
|
||||
newLine();
|
||||
}
|
||||
|
||||
public void attribute(String name, String value) throws DOMException {
|
||||
if (!this.isNude)
|
||||
throw new IllegalArgumentException("Cannot write attribute: too late!");
|
||||
Attr att = this.document.createAttribute(name);
|
||||
att.setValue(value);
|
||||
this.currentElement.appendChild(att);
|
||||
}
|
||||
|
||||
public void attribute(String name, int value) throws DOMException {
|
||||
attribute(name, Integer.toString(value));
|
||||
}
|
||||
|
||||
public void openElement(String name) throws DOMException {
|
||||
openElement(name, false);
|
||||
}
|
||||
|
||||
public void openElement(String name, boolean hasChildren) throws DOMException {
|
||||
deNude();
|
||||
indent();
|
||||
this.childrenFlags.add(Boolean.valueOf(hasChildren));
|
||||
Element element = this.document.createElement(name);
|
||||
this.currentElement.appendChild(element);
|
||||
this.currentElement = element;
|
||||
this.isNude = true;
|
||||
this.depth++;
|
||||
}
|
||||
|
||||
public void element(String name, String text) throws DOMException {
|
||||
openElement(name);
|
||||
writeText(text);
|
||||
closeElement();
|
||||
}
|
||||
|
||||
public void closeElement() throws DOMException, IllegalCloseElementException {
|
||||
if (this.currentElement.getNodeType() == 9)
|
||||
throw new IllegalCloseElementException();
|
||||
this.depth--;
|
||||
this.isNude = false;
|
||||
Boolean hasChildren = (Boolean)this.childrenFlags.remove(this.childrenFlags.size() - 1);
|
||||
if (hasChildren)
|
||||
indent();
|
||||
this.currentElement.normalize();
|
||||
this.currentElement = this.currentElement.getParentNode();
|
||||
if (this.indent) {
|
||||
Boolean b = this.childrenFlags.get(this.childrenFlags.size() - 1);
|
||||
if (b)
|
||||
newLine();
|
||||
}
|
||||
}
|
||||
|
||||
public void emptyElement(String name) throws DOMException {
|
||||
Element element = this.document.createElement(name);
|
||||
this.currentElement.appendChild(element);
|
||||
}
|
||||
|
||||
public void close() {}
|
||||
|
||||
public void flush() {
|
||||
this.currentElement.normalize();
|
||||
}
|
||||
|
||||
public Document getDocument() {
|
||||
return this.document;
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces.");
|
||||
}
|
||||
|
||||
public void openElement(String uri, String name, boolean hasChildren) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces.");
|
||||
}
|
||||
|
||||
public void emptyElement(String uri, String element) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void setPrefixMapping(String uri, String prefix) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, String value) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
public void attribute(String uri, String name, int value) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This class does not handle namespaces");
|
||||
}
|
||||
|
||||
void indent() {
|
||||
if (this.indent) {
|
||||
StringBuffer out = new StringBuffer(this.depth * this.indentChars.length());
|
||||
for (int i = 0; i < this.depth; i++)
|
||||
out.append(this.indentChars);
|
||||
Node node = this.document.createTextNode(out.toString());
|
||||
this.currentElement.appendChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
private void deNude() {
|
||||
if (this.isNude) {
|
||||
if (this.indent)
|
||||
newLine();
|
||||
this.isNude = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void newLine() {
|
||||
this.currentElement.appendChild(this.newline.cloneNode(false));
|
||||
}
|
||||
|
||||
private static Document newDocument() throws ParserConfigurationException {
|
||||
DocumentBuilder builder = XmlUtils.getNewDocumentBuilder();
|
||||
return builder.newDocument();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
public interface XMLEscape {
|
||||
String toAttributeValue(char[] paramArrayOfchar, int paramInt1, int paramInt2);
|
||||
|
||||
String toAttributeValue(String paramString);
|
||||
|
||||
String toElementText(char[] paramArrayOfchar, int paramInt1, int paramInt2);
|
||||
|
||||
String toElementText(String paramString);
|
||||
|
||||
String getEncoding();
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
public final class XMLEscapeASCII extends XMLEscapeBase implements XMLEscape {
|
||||
public static final XMLEscape ASCII_ESCAPE = new XMLEscapeASCII();
|
||||
|
||||
private static final String ENCODING = "ASCII";
|
||||
|
||||
private XMLEscapeASCII() {
|
||||
super("ASCII");
|
||||
}
|
||||
|
||||
public String toAttributeValue(char[] ch, int off, int len) {
|
||||
StringBuffer out = new StringBuffer(len + len / 10);
|
||||
for (int i = off; i < off + len; i++) {
|
||||
if (ch[i] < ' ') {
|
||||
if (ch[i] == '\t' || ch[i] == '\n' || ch[i] == '\r') {
|
||||
out.append(ch[i]);
|
||||
} else {
|
||||
doNothing();
|
||||
}
|
||||
} else if (ch[i] < '\u0080') {
|
||||
switch (ch[i]) {
|
||||
case '&':
|
||||
out.append("&");
|
||||
break;
|
||||
case '<':
|
||||
out.append("<");
|
||||
break;
|
||||
case '"':
|
||||
out.append(""");
|
||||
break;
|
||||
case '\'':
|
||||
out.append("'");
|
||||
break;
|
||||
default:
|
||||
out.append(ch[i]);
|
||||
break;
|
||||
}
|
||||
} else if (ch[i] < '\u00A0') {
|
||||
doNothing();
|
||||
} else {
|
||||
out.append("&#x").append(ch[i]).append(';');
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public String toElementText(char[] ch, int off, int len) {
|
||||
StringBuffer out = new StringBuffer(len + len / 10);
|
||||
for (int i = off; i < off + len; i++) {
|
||||
if (ch[i] < ' ') {
|
||||
if (ch[i] == '\t' || ch[i] == '\n' || ch[i] == '\r') {
|
||||
out.append(ch[i]);
|
||||
} else {
|
||||
doNothing();
|
||||
}
|
||||
} else if (ch[i] < '\u0080') {
|
||||
switch (ch[i]) {
|
||||
case '&':
|
||||
out.append("&");
|
||||
break;
|
||||
case '<':
|
||||
out.append("<");
|
||||
break;
|
||||
default:
|
||||
out.append(ch[i]);
|
||||
break;
|
||||
}
|
||||
} else if (ch[i] < '\u00A0') {
|
||||
doNothing();
|
||||
} else {
|
||||
out.append("&#x").append(ch[i]).append(';');
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private void doNothing() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
abstract class XMLEscapeBase implements XMLEscape {
|
||||
private final String encoding;
|
||||
|
||||
XMLEscapeBase(String encoding) {
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
public final String toAttributeValue(String value) {
|
||||
if (value == null || "".equals(value))
|
||||
return value;
|
||||
return toAttributeValue(value.toCharArray(), 0, value.length());
|
||||
}
|
||||
|
||||
public final String toElementText(String value) {
|
||||
if (value == null || "".equals(value))
|
||||
return value;
|
||||
return toElementText(value.toCharArray(), 0, value.length());
|
||||
}
|
||||
|
||||
public final String getEncoding() {
|
||||
return this.encoding;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
public final class XMLEscapeFactory {
|
||||
public static XMLEscape getInstance(String encoding) {
|
||||
if ("utf-8".equals(encoding))
|
||||
return XMLEscapeUTF8.UTF8_ESCAPE;
|
||||
if ("UTF-8".equals(encoding))
|
||||
return XMLEscapeUTF8.UTF8_ESCAPE;
|
||||
if ("ASCII".equals(encoding))
|
||||
return XMLEscapeASCII.ASCII_ESCAPE;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
public final class XMLEscapeUTF8 extends XMLEscapeBase implements XMLEscape {
|
||||
public static final XMLEscape UTF8_ESCAPE = new XMLEscapeUTF8();
|
||||
|
||||
private static final String ENCODING = "utf-8";
|
||||
|
||||
private XMLEscapeUTF8() {
|
||||
super("utf-8");
|
||||
}
|
||||
|
||||
public String toAttributeValue(char[] ch, int off, int len) {
|
||||
StringBuffer out = new StringBuffer(len + len / 10);
|
||||
for (int i = off; i < off + len; i++) {
|
||||
switch (ch[i]) {
|
||||
case '\000':
|
||||
case '\001':
|
||||
case '\002':
|
||||
case '\003':
|
||||
case '\004':
|
||||
case '\005':
|
||||
case '\006':
|
||||
case '\007':
|
||||
case '\b':
|
||||
case '\013':
|
||||
case '\f':
|
||||
case '\016':
|
||||
case '\017':
|
||||
case '\020':
|
||||
case '\021':
|
||||
case '\022':
|
||||
case '\023':
|
||||
case '\024':
|
||||
case '\025':
|
||||
case '\026':
|
||||
case '\027':
|
||||
case '\030':
|
||||
case '\031':
|
||||
case '\032':
|
||||
case '\033':
|
||||
case '\034':
|
||||
case '\035':
|
||||
case '\036':
|
||||
case '\037':
|
||||
case '\u007F':
|
||||
break;
|
||||
case '&':
|
||||
out.append("&");
|
||||
break;
|
||||
case '<':
|
||||
out.append("<");
|
||||
break;
|
||||
case '"':
|
||||
out.append(""");
|
||||
break;
|
||||
case '\'':
|
||||
out.append("'");
|
||||
break;
|
||||
default:
|
||||
out.append(ch[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public String toElementText(char[] ch, int off, int len) {
|
||||
StringBuffer out = new StringBuffer(len + len / 10);
|
||||
for (int i = off; i < off + len; i++) {
|
||||
switch (ch[i]) {
|
||||
case '\000':
|
||||
case '\001':
|
||||
case '\002':
|
||||
case '\003':
|
||||
case '\004':
|
||||
case '\005':
|
||||
case '\006':
|
||||
case '\007':
|
||||
case '\b':
|
||||
case '\013':
|
||||
case '\f':
|
||||
case '\016':
|
||||
case '\017':
|
||||
case '\020':
|
||||
case '\021':
|
||||
case '\022':
|
||||
case '\023':
|
||||
case '\024':
|
||||
case '\025':
|
||||
case '\026':
|
||||
case '\027':
|
||||
case '\030':
|
||||
case '\031':
|
||||
case '\032':
|
||||
case '\033':
|
||||
case '\034':
|
||||
case '\035':
|
||||
case '\036':
|
||||
case '\037':
|
||||
case '\u007F':
|
||||
break;
|
||||
case '&':
|
||||
out.append("&");
|
||||
break;
|
||||
case '<':
|
||||
out.append("<");
|
||||
break;
|
||||
default:
|
||||
out.append(ch[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface XMLEscapeWriter {
|
||||
void writeAttValue(char[] paramArrayOfchar, int paramInt1, int paramInt2) throws IOException;
|
||||
|
||||
void writeAttValue(String paramString) throws IOException;
|
||||
|
||||
void writeText(char[] paramArrayOfchar, int paramInt1, int paramInt2) throws IOException;
|
||||
|
||||
void writeText(String paramString) throws IOException;
|
||||
|
||||
void writeText(char paramChar) throws IOException;
|
||||
|
||||
String getEncoding();
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.topologi.diffx.xml.esc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
public final class XMLEscapeWriterASCII extends XMLEscapeWriterBase implements XMLEscapeWriter {
|
||||
private static final String ENCODING = "ASCII";
|
||||
|
||||
public XMLEscapeWriterASCII(Writer writer) throws NullPointerException {
|
||||
super(writer, "ASCII");
|
||||
}
|
||||
|
||||
public void writeAttValue(char[] ch, int off, int len) throws IOException {
|
||||
char c = ' ';
|
||||
for (int i = off; i < off + len; i++) {
|
||||
c = ch[i];
|
||||
if (c == '<') {
|
||||
this.w.write("<");
|
||||
} else if (c == '>') {
|
||||
this.w.write(">");
|
||||
} else if (c == '&') {
|
||||
this.w.write("&");
|
||||
} else if (c == '"') {
|
||||
this.w.write(""");
|
||||
} else if (c == '\'') {
|
||||
this.w.write("'");
|
||||
} else if (c > 'ÿ') {
|
||||
this.w.write("&#" + c + ";");
|
||||
} else if (c == '\n' || c == '\r' || c == '\t') {
|
||||
this.w.write(c);
|
||||
} else if (c < ' ') {
|
||||
doNothing();
|
||||
} else if (c >= '\u007F' && c < '\u00A0') {
|
||||
doNothing();
|
||||
} else {
|
||||
this.w.write(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeText(char c) throws IOException {
|
||||
if (c == '<') {
|
||||
this.w.write("<");
|
||||
} else if (c == '>') {
|
||||
this.w.write(">");
|
||||
} else if (c == '&') {
|
||||
this.w.write("&");
|
||||
} else if (c == '"') {
|
||||
this.w.write(""");
|
||||
} else if (c == '\'') {
|
||||
this.w.write("'");
|
||||
} else if (c > 'ÿ') {
|
||||
this.w.write("&#" + c + ";");
|
||||
} else if (c == '\n' || c == '\r' || c == '\t') {
|
||||
this.w.write(c);
|
||||
} else if (c < ' ') {
|
||||
doNothing();
|
||||
} else if (c >= '\u007F' && c < '\u00A0') {
|
||||
doNothing();
|
||||
} else {
|
||||
this.w.write(c);
|
||||
}
|
||||
}
|
||||
|
||||
private static void doNothing() {}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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("<");
|
||||
} else if (c == '>') {
|
||||
this.w.write(">");
|
||||
} else if (c == '&') {
|
||||
this.w.write("&");
|
||||
} else if (c == '"') {
|
||||
this.w.write(""");
|
||||
} else if (c == '\'') {
|
||||
this.w.write("'");
|
||||
} else if (c > 'ÿ') {
|
||||
this.w.write("&#" + c + ";");
|
||||
} else if (c == '\n' || c == '\r' || c == '\t') {
|
||||
this.w.write(c);
|
||||
} else if (c < ' ') {
|
||||
doNothing();
|
||||
} else if (c >= '\u007F' && c < '\u00A0') {
|
||||
doNothing();
|
||||
} else {
|
||||
this.w.write(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeText(char c) throws IOException {
|
||||
if (c == '<') {
|
||||
this.w.write("<");
|
||||
} else if (c == '>') {
|
||||
this.w.write(">");
|
||||
} else if (c == '&') {
|
||||
this.w.write("&");
|
||||
} else if (c == '"') {
|
||||
this.w.write(""");
|
||||
} else if (c == '\'') {
|
||||
this.w.write("'");
|
||||
} else if (c > 'ÿ') {
|
||||
this.w.write("&#" + c + ";");
|
||||
} else if (c == '\n' || c == '\r' || c == '\t') {
|
||||
this.w.write(c);
|
||||
} else if (c < ' ') {
|
||||
doNothing();
|
||||
} else if (c >= '\u007F' && c < '\u00A0') {
|
||||
doNothing();
|
||||
} else {
|
||||
this.w.write(c);
|
||||
}
|
||||
}
|
||||
|
||||
private static void doNothing() {}
|
||||
}
|
||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue