|
package test.saxon.streaming.transformerhandler;
|
|
|
|
import org.xml.sax.Attributes;
|
|
import org.xml.sax.ContentHandler;
|
|
import org.xml.sax.Locator;
|
|
import org.xml.sax.SAXException;
|
|
|
|
import javax.xml.transform.Source;
|
|
import javax.xml.transform.Transformer;
|
|
import javax.xml.transform.TransformerException;
|
|
import javax.xml.transform.sax.SAXResult;
|
|
import javax.xml.transform.sax.SAXSource;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.function.Consumer;
|
|
|
|
public class ContentHandlerForwarder implements ContentHandler
|
|
{
|
|
private final List<ContentHandler> listForkedContentHandlers = new ArrayList<>();
|
|
private final Consumer<ContentHandler> forkedContentHandlerConsumer = new Consumer<ContentHandler>()
|
|
{
|
|
@Override
|
|
public void accept(ContentHandler contentHandler)
|
|
{
|
|
listForkedContentHandlers.add(contentHandler);
|
|
}
|
|
};
|
|
|
|
|
|
private ContentHandlerForwarder(Transformer mainTransformer, Source mainSource, Transformation... forkingTransformations) throws TransformerException
|
|
{
|
|
if(forkingTransformations == null || forkingTransformations.length == 0)
|
|
return;
|
|
|
|
Transformation mainTransformation = new Transformation(mainTransformer, mainSource, new SAXResult(this));
|
|
TransformationSequencingXMLReader transformationSequencingXMLReader = new TransformationSequencingXMLReader(mainTransformation, forkedContentHandlerConsumer);
|
|
Transformation forkTransformation = null;
|
|
for(int i = 0; i < forkingTransformations.length; i++)
|
|
{
|
|
forkTransformation = forkingTransformations[i];
|
|
forkTransformation.setSource(new SAXSource(transformationSequencingXMLReader, null));
|
|
transformationSequencingXMLReader = new TransformationSequencingXMLReader(forkTransformation, forkedContentHandlerConsumer);
|
|
}
|
|
//forkTransformation now is the last of the forking transformer
|
|
//calling execute on it will
|
|
// 1. call the transform on the transformer object, which will first set a receiving content handler on the source for this transform
|
|
//which is a transformationChainingXMLReader. The setContentHandler of TransformationChainingXMLReader will pass on that content handler to the consumer
|
|
//which will add it to listForkedContentHandlers
|
|
// 2. call the parse method on transformationChainingXMLReader, which in turn will now call transform on the previous forked transform
|
|
//Thus the transform will be chained across each forked transform, while in each case collecting and storing the receiving content handler of that forked transform
|
|
//in listForkedContentHandlers
|
|
// 3. finally the first forked transform is called and the source assigned to it is the main source and the transformer is the main transformer
|
|
// The result for this main transform is an instance of ContentHandlerForwarder, which will forward the sax events received to every instance in listForkedContentHandlers
|
|
forkTransformation.execute();
|
|
}
|
|
|
|
public static void forkResult(Transformer mainTransformer, Source mainSource, Transformation... forkingTransformations) throws TransformerException
|
|
{
|
|
new ContentHandlerForwarder(mainTransformer, mainSource, forkingTransformations);
|
|
}
|
|
|
|
@Override
|
|
public void setDocumentLocator(Locator locator)
|
|
{
|
|
for(ContentHandler forkedContentHandler : listForkedContentHandlers)
|
|
forkedContentHandler.setDocumentLocator(locator);
|
|
}
|
|
|
|
@Override
|
|
public void endDocument() throws SAXException
|
|
{
|
|
for(ContentHandler forkedContentHandler : listForkedContentHandlers)
|
|
forkedContentHandler.endDocument();
|
|
}
|
|
|
|
@Override
|
|
public void startDocument() throws SAXException
|
|
{
|
|
for(ContentHandler forkedContentHandler : listForkedContentHandlers)
|
|
forkedContentHandler.startDocument();
|
|
}
|
|
|
|
@Override
|
|
public void startPrefixMapping(String prefix, String uri) throws SAXException
|
|
{
|
|
for(ContentHandler forkedContentHandler : listForkedContentHandlers)
|
|
forkedContentHandler.startPrefixMapping(prefix, uri);
|
|
}
|
|
|
|
@Override
|
|
public void endPrefixMapping(String prefix) throws SAXException
|
|
{
|
|
for(ContentHandler forkedContentHandler : listForkedContentHandlers)
|
|
forkedContentHandler.endPrefixMapping(prefix);
|
|
}
|
|
|
|
@Override
|
|
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException
|
|
{
|
|
for(ContentHandler forkedContentHandler : listForkedContentHandlers)
|
|
forkedContentHandler.startElement(uri, localName, qName, atts);
|
|
}
|
|
|
|
@Override
|
|
public void endElement(String uri, String localName, String qName) throws SAXException
|
|
{
|
|
for(ContentHandler forkedContentHandler : listForkedContentHandlers)
|
|
forkedContentHandler.endElement(uri, localName, qName);
|
|
}
|
|
|
|
@Override
|
|
public void characters(char[] ch, int start, int length) throws SAXException
|
|
{
|
|
for(ContentHandler forkedContentHandler : listForkedContentHandlers)
|
|
forkedContentHandler.characters(ch, start, length);
|
|
}
|
|
|
|
@Override
|
|
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
|
|
{
|
|
for(ContentHandler forkedContentHandler : listForkedContentHandlers)
|
|
forkedContentHandler.ignorableWhitespace(ch, start, length);
|
|
}
|
|
|
|
@Override
|
|
public void processingInstruction(String target, String data) throws SAXException
|
|
{
|
|
for(ContentHandler forkedContentHandler : listForkedContentHandlers)
|
|
forkedContentHandler.processingInstruction(target, data);
|
|
}
|
|
|
|
@Override
|
|
public void skippedEntity(String name) throws SAXException
|
|
{
|
|
for(ContentHandler forkedContentHandler : listForkedContentHandlers)
|
|
forkedContentHandler.skippedEntity(name);
|
|
}
|
|
}
|