public void endElementIO(String namespaceURI, String localName, String rawName) throws IOException { ElementState state; if (DEBUG) { System.out.println("==>endElement: " + rawName); } // Works much like content() with additions for closing // an element. Note the different checks for the closed // element's state and the parent element's state. _printer.unindent(); state = getElementState(); if (state.empty) { _printer.printText("/>"); } else { // Must leave CData section first if (state.inCData) _printer.printText("]]>"); // This element is not empty and that last content was // another element, so print a line break before that // last element and this element's closing tag. if (_indenting && !state.preserveSpace && (state.afterElement || state.afterComment)) _printer.breakLine(); _printer.printText("</"); _printer.printText(state.rawName); _printer.printText('>'); } // Leave the element state and update that of the parent // (if we're not root) to not empty and after element. state = leaveElementState(); state.afterElement = true; state.afterComment = false; state.empty = false; if (isDocumentState()) _printer.flush(); }
/** * Print information when the algorithm gets lost in the matrix, ie when it does not know which * direction to follow. * * @param i The X position. * @param j The Y position. */ 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=" + matrix.get(i + 1, j)); System.err.println(" value in Y+1=" + matrix.get(i, j + 1)); System.err.println(" equals=" + e1.equals(e2)); System.err.println(" greaterX=" + matrix.isGreaterX(i, j)); System.err.println(" greaterY=" + matrix.isGreaterY(i, j)); System.err.println(" sameXY=" + matrix.isSameXY(i, j)); System.err.println(" okFormat1=" + estate.okFormat(e1)); System.err.println(" okFormat2=" + estate.okFormat(e2)); System.err.println(" okInsert=" + estate.okInsert(e1)); System.err.println(" okDelete=" + estate.okDelete(e2)); }
/** * Called to serialize a DOM element. Equivalent to calling {@link #startElement}, {@link * #endElement} and serializing everything inbetween, but better optimized. */ protected void serializeElement(Element elem) throws IOException { Attr attr; NamedNodeMap attrMap; int i; Node child; ElementState state; String name; String value; String tagName; String prefix, localUri; String uri; if (fNamespaces) { // local binder stores namespace declaration // that has been printed out during namespace fixup of // the current element fLocalNSBinder.reset(); // add new namespace context fNSBinder.pushContext(); } if (DEBUG) { System.out.println( "==>startElement: " + elem.getNodeName() + " ns=" + elem.getNamespaceURI()); } tagName = elem.getTagName(); state = getElementState(); if (isDocumentState()) { // If this is the root element handle it differently. // If the first root element in the document, serialize // the document's DOCTYPE. Space preserving defaults // to that of the output format. if (!_started) { startDocument(tagName); } } else { // For any other element, if first in parent, then // close parent's opening tag and use the parent's // space preserving. if (state.empty) _printer.printText('>'); // Must leave CData section first if (state.inCData) { _printer.printText("]]>"); state.inCData = false; } // Indent this element on a new line if the first // content of the parent element or immediately // following an element. if (_indenting && !state.preserveSpace && (state.empty || state.afterElement || state.afterComment)) _printer.breakLine(); } // Do not change the current element state yet. // This only happens in endElement(). fPreserveSpace = state.preserveSpace; int length = 0; attrMap = null; // retrieve attributes if (elem.hasAttributes()) { attrMap = elem.getAttributes(); length = attrMap.getLength(); } if (!fNamespaces) { // no namespace fixup should be performed // serialize element name _printer.printText('<'); _printer.printText(tagName); _printer.indent(); // For each attribute print it's name and value as one part, // separated with a space so the element can be broken on // multiple lines. for (i = 0; i < length; ++i) { attr = (Attr) attrMap.item(i); name = attr.getName(); value = attr.getValue(); if (value == null) value = ""; printAttribute(name, value, attr.getSpecified(), attr); } } else { // do namespace fixup // REVISIT: some optimization could probably be done to avoid traversing // attributes twice. // // --------------------------------------- // record all valid namespace declarations // before attempting to fix element's namespace // --------------------------------------- for (i = 0; i < length; i++) { attr = (Attr) attrMap.item(i); uri = attr.getNamespaceURI(); // check if attribute is a namespace decl if (uri != null && uri.equals(NamespaceContext.XMLNS_URI)) { value = attr.getNodeValue(); if (value == null) { value = XMLSymbols.EMPTY_STRING; } if (value.equals(NamespaceContext.XMLNS_URI)) { if (fDOMErrorHandler != null) { String msg = DOMMessageFormatter.formatMessage( DOMMessageFormatter.XML_DOMAIN, "CantBindXMLNS", null); modifyDOMError(msg, DOMError.SEVERITY_ERROR, null, attr); boolean continueProcess = fDOMErrorHandler.handleError(fDOMError); if (!continueProcess) { // stop the namespace fixup and validation throw new RuntimeException( DOMMessageFormatter.formatMessage( DOMMessageFormatter.SERIALIZER_DOMAIN, "SerializationStopped", null)); } } } else { prefix = attr.getPrefix(); prefix = (prefix == null || prefix.length() == 0) ? XMLSymbols.EMPTY_STRING : fSymbolTable.addSymbol(prefix); String localpart = fSymbolTable.addSymbol(attr.getLocalName()); if (prefix == XMLSymbols.PREFIX_XMLNS) { // xmlns:prefix value = fSymbolTable.addSymbol(value); // record valid decl if (value.length() != 0) { fNSBinder.declarePrefix(localpart, value); } else { // REVISIT: issue error on invalid declarations // xmlns:foo = "" } continue; } else { // xmlns // empty prefix is always bound ("" or some string) value = fSymbolTable.addSymbol(value); fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, value); continue; } } // end-else: valid declaration } // end-if: namespace declaration } // end-for // ----------------------- // get element uri/prefix // ----------------------- uri = elem.getNamespaceURI(); prefix = elem.getPrefix(); // ---------------------- // output element name // ---------------------- // REVISIT: this could be removed if we always convert empty string to null // for the namespaces. if ((uri != null && prefix != null) && uri.length() == 0 && prefix.length() != 0) { // uri is an empty string and element has some prefix // the namespace alg later will fix up the namespace attributes // remove element prefix prefix = null; _printer.printText('<'); _printer.printText(elem.getLocalName()); _printer.indent(); } else { _printer.printText('<'); _printer.printText(tagName); _printer.indent(); } // --------------------------------------------------------- // Fix up namespaces for element: per DOM L3 // Need to consider the following cases: // // case 1: <foo:elem xmlns:ns1="myURI" xmlns="default"/> // Assume "foo", "ns1" are declared on the parent. We should not miss // redeclaration for both "ns1" and default namespace. To solve this // we add a local binder that stores declaration only for current element. // This way we avoid outputing duplicate declarations for the same element // as well as we are not omitting redeclarations. // // case 2: <elem xmlns="" xmlns="default"/> // We need to bind default namespace to empty string, to be able to // omit duplicate declarations for the same element // // case 3: <xsl:stylesheet xmlns:xsl="http://xsl"> // We create another element body bound to the "http://xsl" namespace // as well as namespace attribute rebounding xsl to another namespace. // <xsl:body xmlns:xsl="http://another"> // Need to make sure that the new namespace decl value is changed to // "http://xsl" // // --------------------------------------------------------- // check if prefix/namespace is correct for current element // --------------------------------------------------------- if (uri != null) { // Element has a namespace uri = fSymbolTable.addSymbol(uri); prefix = (prefix == null || prefix.length() == 0) ? XMLSymbols.EMPTY_STRING : fSymbolTable.addSymbol(prefix); if (fNSBinder.getURI(prefix) == uri) { // The xmlns:prefix=namespace or xmlns="default" was declared at parent. // The binder always stores mapping of empty prefix to "". // (NOTE: local binder does not store this kind of binding!) // Thus the case where element was declared with uri="" (with or without a prefix) // will be covered here. } else { // the prefix is either undeclared // or // conflict: the prefix is bound to another URI if (fNamespacePrefixes) { printNamespaceAttr(prefix, uri); } fLocalNSBinder.declarePrefix(prefix, uri); fNSBinder.declarePrefix(prefix, uri); } } else { // Element has no namespace if (elem.getLocalName() == null) { // DOM Level 1 node! if (fDOMErrorHandler != null) { String msg = DOMMessageFormatter.formatMessage( DOMMessageFormatter.DOM_DOMAIN, "NullLocalElementName", new Object[] {elem.getNodeName()}); modifyDOMError(msg, DOMError.SEVERITY_ERROR, null, elem); boolean continueProcess = fDOMErrorHandler.handleError(fDOMError); // REVISIT: should we terminate upon request? if (!continueProcess) { throw new RuntimeException( DOMMessageFormatter.formatMessage( DOMMessageFormatter.SERIALIZER_DOMAIN, "SerializationStopped", null)); } } } else { // uri=null and no colon (DOM L2 node) uri = fNSBinder.getURI(XMLSymbols.EMPTY_STRING); if (uri != null && uri.length() > 0) { // there is a default namespace decl that is bound to // non-zero length uri, output xmlns="" if (fNamespacePrefixes) { printNamespaceAttr(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING); } fLocalNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING); fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING); } } } // ----------------------------------------- // Fix up namespaces for attributes: per DOM L3 // check if prefix/namespace is correct the attributes // ----------------------------------------- for (i = 0; i < length; i++) { attr = (Attr) attrMap.item(i); value = attr.getValue(); name = attr.getNodeName(); uri = attr.getNamespaceURI(); // Fix attribute that was declared with a prefix and namespace="" if (uri != null && uri.length() == 0) { uri = null; // we must remove prefix for this attribute name = attr.getLocalName(); } if (DEBUG) { System.out.println("==>process attribute: " + attr.getNodeName()); } // make sure that value is never null. if (value == null) { value = XMLSymbols.EMPTY_STRING; } if (uri != null) { // attribute has namespace !=null prefix = attr.getPrefix(); prefix = prefix == null ? XMLSymbols.EMPTY_STRING : fSymbolTable.addSymbol(prefix); String localpart = fSymbolTable.addSymbol(attr.getLocalName()); // --------------------------------------------------- // print namespace declarations namespace declarations // --------------------------------------------------- if (uri != null && uri.equals(NamespaceContext.XMLNS_URI)) { // check if we need to output this declaration prefix = attr.getPrefix(); prefix = (prefix == null || prefix.length() == 0) ? XMLSymbols.EMPTY_STRING : fSymbolTable.addSymbol(prefix); localpart = fSymbolTable.addSymbol(attr.getLocalName()); if (prefix == XMLSymbols.PREFIX_XMLNS) { // xmlns:prefix localUri = fLocalNSBinder.getURI(localpart); // local prefix mapping value = fSymbolTable.addSymbol(value); if (value.length() != 0) { if (localUri == null) { // declaration was not printed while fixing element namespace binding // If the DOM Level 3 namespace-prefixes feature is set to false // do not print xmlns attributes if (fNamespacePrefixes) { printNamespaceAttr(localpart, value); } // case 4: <elem xmlns:xx="foo" xx:attr=""/> // where attribute is bound to "bar". // If the xmlns:xx is output here first, later we should not // redeclare "xx" prefix. Instead we would pick up different prefix // for the attribute. // final: <elem xmlns:xx="foo" NS1:attr="" xmlns:NS1="bar"/> fLocalNSBinder.declarePrefix(localpart, value); } } else { // REVISIT: issue error on invalid declarations // xmlns:foo = "" } continue; } else { // xmlns // empty prefix is always bound ("" or some string) uri = fNSBinder.getURI(XMLSymbols.EMPTY_STRING); localUri = fLocalNSBinder.getURI(XMLSymbols.EMPTY_STRING); value = fSymbolTable.addSymbol(value); if (localUri == null) { // declaration was not printed while fixing element namespace binding if (fNamespacePrefixes) { printNamespaceAttr(XMLSymbols.EMPTY_STRING, value); } // case 4 does not apply here since attributes can't use // default namespace } continue; } } uri = fSymbolTable.addSymbol(uri); // find if for this prefix a URI was already declared String declaredURI = fNSBinder.getURI(prefix); if (prefix == XMLSymbols.EMPTY_STRING || declaredURI != uri) { // attribute has no prefix (default namespace decl does not apply to attributes) // OR // attribute prefix is not declared // OR // conflict: attr URI does not match the prefix in scope name = attr.getNodeName(); // Find if any prefix for attributes namespace URI is available // in the scope String declaredPrefix = fNSBinder.getPrefix(uri); if (declaredPrefix != null && declaredPrefix != XMLSymbols.EMPTY_STRING) { // use the prefix that was found prefix = declaredPrefix; name = prefix + ":" + localpart; } else { if (DEBUG) { System.out.println("==> cound not find prefix for the attribute: " + prefix); } if (prefix != XMLSymbols.EMPTY_STRING && fLocalNSBinder.getURI(prefix) == null) { // the current prefix is not null and it has no in scope declaration // use this prefix } else { // find a prefix following the pattern "NS" +index (starting at 1) // make sure this prefix is not declared in the current scope. int counter = 1; prefix = fSymbolTable.addSymbol(PREFIX + counter++); while (fLocalNSBinder.getURI(prefix) != null) { prefix = fSymbolTable.addSymbol(PREFIX + counter++); } name = prefix + ":" + localpart; } // add declaration for the new prefix if (fNamespacePrefixes) { printNamespaceAttr(prefix, uri); } value = fSymbolTable.addSymbol(value); fLocalNSBinder.declarePrefix(prefix, value); fNSBinder.declarePrefix(prefix, uri); } // change prefix for this attribute } printAttribute( name, (value == null) ? XMLSymbols.EMPTY_STRING : value, attr.getSpecified(), attr); } else { // attribute uri == null if (attr.getLocalName() == null) { if (fDOMErrorHandler != null) { String msg = DOMMessageFormatter.formatMessage( DOMMessageFormatter.DOM_DOMAIN, "NullLocalAttrName", new Object[] {attr.getNodeName()}); modifyDOMError(msg, DOMError.SEVERITY_ERROR, null, attr); boolean continueProcess = fDOMErrorHandler.handleError(fDOMError); if (!continueProcess) { // stop the namespace fixup and validation throw new RuntimeException( DOMMessageFormatter.formatMessage( DOMMessageFormatter.SERIALIZER_DOMAIN, "SerializationStopped", null)); } } printAttribute(name, value, attr.getSpecified(), attr); } else { // uri=null and no colon // no fix up is needed: default namespace decl does not // apply to attributes printAttribute(name, value, attr.getSpecified(), attr); } } } // end loop for attributes } // end namespace fixup algorithm // If element has children, then serialize them, otherwise // serialize en empty tag. if (elem.hasChildNodes()) { // Enter an element state, and serialize the children // one by one. Finally, end the element. state = enterElementState(null, null, tagName, fPreserveSpace); state.doCData = _format.isCDataElement(tagName); state.unescaped = _format.isNonEscapingElement(tagName); child = elem.getFirstChild(); while (child != null) { serializeNode(child); child = child.getNextSibling(); } if (fNamespaces) { fNSBinder.popContext(); } endElementIO(null, null, tagName); } else { if (DEBUG) { System.out.println("==>endElement: " + elem.getNodeName()); } if (fNamespaces) { fNSBinder.popContext(); } _printer.unindent(); _printer.printText("/>"); // After element but parent element is no longer empty. state.afterElement = true; state.afterComment = false; state.empty = false; if (isDocumentState()) _printer.flush(); } }
public void startElement(String tagName, AttributeList attrs) throws SAXException { int i; boolean preserveSpace; ElementState state; String name; String value; if (DEBUG) { System.out.println("==>startElement(" + tagName + ")"); } try { if (_printer == null) { String msg = DOMMessageFormatter.formatMessage( DOMMessageFormatter.SERIALIZER_DOMAIN, "NoWriterSupplied", null); throw new IllegalStateException(msg); } state = getElementState(); if (isDocumentState()) { // If this is the root element handle it differently. // If the first root element in the document, serialize // the document's DOCTYPE. Space preserving defaults // to that of the output format. if (!_started) startDocument(tagName); } else { // For any other element, if first in parent, then // close parent's opening tag and use the parnet's // space preserving. if (state.empty) _printer.printText('>'); // Must leave CData section first if (state.inCData) { _printer.printText("]]>"); state.inCData = false; } // Indent this element on a new line if the first // content of the parent element or immediately // following an element. if (_indenting && !state.preserveSpace && (state.empty || state.afterElement || state.afterComment)) _printer.breakLine(); } preserveSpace = state.preserveSpace; // Do not change the current element state yet. // This only happens in endElement(). _printer.printText('<'); _printer.printText(tagName); _printer.indent(); // For each attribute print it's name and value as one part, // separated with a space so the element can be broken on // multiple lines. if (attrs != null) { for (i = 0; i < attrs.getLength(); ++i) { _printer.printSpace(); name = attrs.getName(i); value = attrs.getValue(i); if (value != null) { _printer.printText(name); _printer.printText("=\""); printEscaped(value); _printer.printText('"'); } // If the attribute xml:space exists, determine whether // to preserve spaces in this and child nodes based on // its value. if (name.equals("xml:space")) { if (value.equals("preserve")) preserveSpace = true; else preserveSpace = _format.getPreserveSpace(); } } } // Now it's time to enter a new element state // with the tag name and space preserving. // We still do not change the curent element state. state = enterElementState(null, null, tagName, preserveSpace); state.doCData = _format.isCDataElement(tagName); state.unescaped = _format.isNonEscapingElement(tagName); } catch (IOException except) { throw new SAXException(except); } }
public void startElement(String namespaceURI, String localName, String rawName, Attributes attrs) throws SAXException { int i; boolean preserveSpace; ElementState state; String name; String value; boolean addNSAttr = false; if (DEBUG) { System.out.println("==>startElement(" + namespaceURI + "," + localName + "," + rawName + ")"); } try { if (_printer == null) { String msg = DOMMessageFormatter.formatMessage( DOMMessageFormatter.SERIALIZER_DOMAIN, "NoWriterSupplied", null); throw new IllegalStateException(msg); } state = getElementState(); if (isDocumentState()) { // If this is the root element handle it differently. // If the first root element in the document, serialize // the document's DOCTYPE. Space preserving defaults // to that of the output format. if (!_started) startDocument((localName == null || localName.length() == 0) ? rawName : localName); } else { // For any other element, if first in parent, then // close parent's opening tag and use the parnet's // space preserving. if (state.empty) _printer.printText('>'); // Must leave CData section first if (state.inCData) { _printer.printText("]]>"); state.inCData = false; } // Indent this element on a new line if the first // content of the parent element or immediately // following an element or a comment if (_indenting && !state.preserveSpace && (state.empty || state.afterElement || state.afterComment)) _printer.breakLine(); } preserveSpace = state.preserveSpace; // We remove the namespaces from the attributes list so that they will // be in _prefixes attrs = extractNamespaces(attrs); // Do not change the current element state yet. // This only happens in endElement(). if (rawName == null || rawName.length() == 0) { if (localName == null) { String msg = DOMMessageFormatter.formatMessage( DOMMessageFormatter.SERIALIZER_DOMAIN, "NoName", null); throw new SAXException(msg); } if (namespaceURI != null && !namespaceURI.equals("")) { String prefix; prefix = getPrefix(namespaceURI); if (prefix != null && prefix.length() > 0) rawName = prefix + ":" + localName; else rawName = localName; } else rawName = localName; addNSAttr = true; } _printer.printText('<'); _printer.printText(rawName); _printer.indent(); // For each attribute print it's name and value as one part, // separated with a space so the element can be broken on // multiple lines. if (attrs != null) { for (i = 0; i < attrs.getLength(); ++i) { _printer.printSpace(); name = attrs.getQName(i); if (name != null && name.length() == 0) { String prefix; String attrURI; name = attrs.getLocalName(i); attrURI = attrs.getURI(i); if ((attrURI != null && attrURI.length() != 0) && (namespaceURI == null || namespaceURI.length() == 0 || !attrURI.equals(namespaceURI))) { prefix = getPrefix(attrURI); if (prefix != null && prefix.length() > 0) name = prefix + ":" + name; } } value = attrs.getValue(i); if (value == null) value = ""; _printer.printText(name); _printer.printText("=\""); printEscaped(value); _printer.printText('"'); // If the attribute xml:space exists, determine whether // to preserve spaces in this and child nodes based on // its value. if (name.equals("xml:space")) { if (value.equals("preserve")) preserveSpace = true; else preserveSpace = _format.getPreserveSpace(); } } } if (_prefixes != null) { Enumeration keys; keys = _prefixes.keys(); while (keys.hasMoreElements()) { _printer.printSpace(); value = (String) keys.nextElement(); name = (String) _prefixes.get(value); if (name.length() == 0) { _printer.printText("xmlns=\""); printEscaped(value); _printer.printText('"'); } else { _printer.printText("xmlns:"); _printer.printText(name); _printer.printText("=\""); printEscaped(value); _printer.printText('"'); } } } // Now it's time to enter a new element state // with the tag name and space preserving. // We still do not change the curent element state. state = enterElementState(namespaceURI, localName, rawName, preserveSpace); name = (localName == null || localName.length() == 0) ? rawName : namespaceURI + "^" + localName; state.doCData = _format.isCDataElement(name); state.unescaped = _format.isNonEscapingElement(name); } catch (IOException except) { throw new SAXException(except); } }
/** * Writes the diff sequence using the specified formatter. * * @param formatter The formatter that will handle the output. * @throws IOException If thrown by the formatter. */ public void process(DiffXFormatter formatter) throws IOException { // handle the case when one of the two sequences is empty processEmpty(formatter); Docx4jDriver.log("length first: " + this.length1); Docx4jDriver.log("length second: " + this.length2); if (this.length1 == 0 || this.length2 == 0) return; // Phase I: calculate the LCS length to fill the matrix (slow for lengths in order of > 10^2) long startTime = System.currentTimeMillis(); length(); long endTime = System.currentTimeMillis(); long duration = endTime - startTime; Docx4jDriver.log("diffx LCS phase took: " + duration + " ms "); int i = 0; int j = 0; DiffXEvent e1 = sequence1.getEvent(i); DiffXEvent e2 = sequence2.getEvent(j); // Phase II: start walking the matrix (this should be quick) while (i < super.length1 && j < super.length2) { e1 = sequence1.getEvent(i); e2 = sequence2.getEvent(j); // we can only insert or delete, priority to insert if (matrix.isGreaterX(i, j)) { // follow the natural path and insert if (estate.okInsert(e1)) { if (DEBUG) System.err.print(" >i +" + ShortStringFormatter.toShortString(e1)); formatter.insert(e1); estate.insert(e1); i++; // if we can format checking at the stack, let's do it } else if (e1.equals(e2) && estate.okFormat(e1)) { if (DEBUG) System.err.print(" <f " + ShortStringFormatter.toShortString(e1)); formatter.format(e1); estate.format(e1); i++; j++; // go counter current and delete } else if (estate.okDelete(e2)) { if (DEBUG) System.err.print(" >d -" + ShortStringFormatter.toShortString(e2)); formatter.delete(e2); estate.delete(e2); j++; } else { if (DEBUG) System.err.print("\n(i) case greater X"); if (DEBUG) printLost(i, j); break; } // we can only insert or delete, priority to delete } else if (matrix.isGreaterY(i, j)) { // follow the natural and delete if (estate.okDelete(e2)) { if (DEBUG) System.err.print(" <d -" + ShortStringFormatter.toShortString(e2)); formatter.delete(e2); estate.delete(e2); j++; // if we can format checking at the stack, let's do it } else if (e1.equals(e2) && estate.okFormat(e1)) { if (DEBUG) System.err.print(" <f " + ShortStringFormatter.toShortString(e1)); formatter.format(e1); estate.format(e1); i++; j++; // insert (counter-current) } else if (estate.okInsert(e1)) { if (DEBUG) System.err.print(" <i +" + ShortStringFormatter.toShortString(e2)); formatter.insert(e1); estate.insert(e1); i++; } else { if (DEBUG) System.err.println("\n(i) case greater Y"); if (DEBUG) printLost(i, j); break; } // elements from i inserted and j deleted // we have to make a choice for where we are going } else if (matrix.isSameXY(i, j)) { // if we can format checking at the stack, let's do it if (e1.equals(e2) && estate.okFormat(e1)) { if (DEBUG) System.err.print(" =f " + ShortStringFormatter.toShortString(e1)); formatter.format(e1); estate.format(e1); i++; j++; // we can insert the closing tag } else if (estate.okInsert(e1) && !(e2 instanceof AttributeEvent && !(e1 instanceof AttributeEvent))) { if (DEBUG) System.err.print(" =i +" + ShortStringFormatter.toShortString(e1)); estate.insert(e1); formatter.insert(e1); i++; // we can delete the closing tag } else if (estate.okDelete(e2) && !(e1 instanceof AttributeEvent && !(e2 instanceof AttributeEvent))) { if (DEBUG) System.err.print(" =d -" + ShortStringFormatter.toShortString(e2)); formatter.delete(e2); estate.delete(e2); j++; } else { if (DEBUG) System.err.println("\n(i) case same"); if (DEBUG) printLost(i, j); break; } } else { if (DEBUG) System.err.println("\n(i) case ???"); if (DEBUG) printLost(i, j); break; } if (DEBUG) System.err.println( " stack=" + estate.currentChange() + ShortStringFormatter.toShortString(estate.current())); } // finish off the events from the first sequence while (i < super.length1) { estate.insert(sequence1.getEvent(i)); formatter.insert(sequence1.getEvent(i)); i++; } // finish off the events from the second sequence while (j < super.length2) { estate.delete(sequence2.getEvent(j)); formatter.delete(sequence2.getEvent(j)); j++; } // free some resources // matrix.release(); }