Added single-tag vs dual-tag distinction to strict parser

This commit is contained in:
Vhati 2013-08-27 23:34:26 -04:00
parent 270f4314d6
commit 45b26c5f7e

View file

@ -0,0 +1,124 @@
package net.vhati.modmanager.core;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.jdom2.Element;
import org.jdom2.JDOMFactory;
import org.jdom2.Parent;
import org.jdom2.Text;
import org.jdom2.input.sax.SAXHandler;
import org.jdom2.input.sax.SAXHandlerFactory;
/**
* A factory that produces SAXHandlers which distinguish tag-pairs from dual tags.
*
* While this factory is registered with a SAXBuilder, strict parsing
* will occur as normal, notifying the SAXHandler of progress. When
* the handler hears that a tag ended at a different line/column than
* where it started, and no other text was reported along the way, a
* zero-length text node will be added as token content.
*
* Later, when the Element tree is printed, a special
* XMLOutputProcessor can reproduce the tag pair pased on the
* presence of child Content objects - like the dummy string - rather
* than the presence of non-whitespace text after formatting.
*
* Note: Not all XMLReaders offer a Locator for line/col info. When
* that info is not available, this handler will do nothing special.
*
* @see org.jdom2.input.SAXBuilder#setSAXHandlerFactory(SAXHandlerFactory factory)
*/
public class EmptyAwareSAXHandlerFactory implements SAXHandlerFactory {
@Override
public SAXHandler createSAXHandler( JDOMFactory factory ) {
return new EmptyAwareSAXHandler( factory );
}
public static class EmptyAwareSAXHandler extends SAXHandler {
boolean emptyTag = true;
int startTagLine = -1;
int startTagColumn = -1;
public EmptyAwareSAXHandler( JDOMFactory factory ) {
super( factory );
}
@Override
public void startElement( String namespaceURI, String localName, String qName, Attributes atts ) throws SAXException {
emptyTag = true;
startTagLine = -1;
startTagColumn = -1;
Locator loc = getDocumentLocator();
if ( loc != null ) {
startTagLine = loc.getLineNumber();
startTagColumn = loc.getColumnNumber();
}
super.startElement( namespaceURI, localName, qName, atts );
}
@Override
public void comment( char[] ch, final int start, final int length ) throws SAXException {
emptyTag = false;
super.comment( ch, start, length );
}
@Override
public void characters( char[] ch, final int start, final int length ) throws SAXException {
emptyTag = false;
super.characters( ch, start, length );
}
@Override
public void ignorableWhitespace( char[] ch, int start, int length) throws SAXException {
emptyTag = false;
super.characters( ch, start, length );
}
@Override
public void processingInstruction( String target, String data ) throws SAXException {
super.processingInstruction( target, data );
}
@Override
public void startCDATA() {
emptyTag = false;
super.startCDATA();
}
@Override
public void endElement( String namespaceURI, String localName, String qName ) throws SAXException {
Element closedElement = getCurrentElement();
boolean twoPartTag = false;
Locator loc = getDocumentLocator();
if ( loc != null ) {
int endTagLine = loc.getLineNumber();
int endTagColumn = loc.getColumnNumber();
if ( startTagLine != -1 && endTagLine != -1 && startTagLine != endTagLine) {
twoPartTag = true;
}
else if ( startTagColumn != -1 && endTagColumn != -1 && startTagColumn != endTagColumn ) {
twoPartTag = true;
}
}
super.endElement( namespaceURI, localName, qName );
if ( emptyTag && twoPartTag && closedElement.getContent().isEmpty() ) {
// This is a separate closing tag after an empty value.
// Add a blank text node.
final Text text = getFactory().text( "" );
getFactory().addContent( closedElement, text );
}
}
}
}