net.sf.saxon.option.xom.XOMWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Saxon-HE Show documentation
Show all versions of Saxon-HE Show documentation
The XSLT and XQuery Processor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2023 Saxonica Limited
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
package net.sf.saxon.option.xom;
import net.sf.saxon.event.PipelineConfiguration;
import net.sf.saxon.event.ReceiverOption;
import net.sf.saxon.s9api.Location;
import net.sf.saxon.om.*;
import net.sf.saxon.str.UnicodeString;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.SchemaType;
import nu.xom.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* XOMWriter is a Receiver that constructs a XOM document from the stream of events
*/
public class XOMWriter extends net.sf.saxon.event.Builder {
private Document document;
private final Stack ancestors = new Stack<>();
private final Stack nsStack = new Stack<>();
private final NodeFactory nodeFactory;
private boolean implicitDocumentNode = false;
private final StringBuilder textBuffer = new StringBuilder(64);
/**
* Create a XOMWriter using the default node factory
*
* @param pipe the pipeline configuration
*/
public XOMWriter(/*@NotNull*/ PipelineConfiguration pipe) {
super(pipe);
this.nodeFactory = new NodeFactory();
this.nsStack.push(NamespaceMap.emptyMap());
}
/**
* Create a XOMWriter
*
* @param pipe the pipeline configuration
* @param factory the XOM NodeFactory to be used
*/
public XOMWriter(/*@NotNull*/ PipelineConfiguration pipe, /*@NotNull*/ NodeFactory factory) {
super(pipe);
this.nodeFactory = factory;
this.nsStack.push(NamespaceMap.emptyMap());
}
/**
* Notify an unparsed entity URI.
*
* @param name The name of the unparsed entity
* @param systemID The system identifier of the unparsed entity
* @param publicID The public identifier of the unparsed entity
*/
@Override
public void setUnparsedEntity(String name, String systemID, String publicID) throws XPathException {
// no-op
}
/**
* Start of the document.
*/
@Override
public void open() {
}
/**
* End of the document.
*/
@Override
public void close() {
}
/**
* Start of a document node.
* @param properties the properties of the document node
*/
@Override
public void startDocument(int properties) throws XPathException {
document = nodeFactory.startMakingDocument();
try {
document.setBaseURI(systemId);
} catch (MalformedURIException e) {
// XOM objects if the URI is invalid
throw new XPathException(e);
}
ancestors.push(document);
textBuffer.setLength(0);
}
/**
* Notify the end of a document node
*/
@Override
public void endDocument() throws XPathException {
nodeFactory.finishMakingDocument(document);
ancestors.pop();
}
/**
* Start of an element.
*/
@Override
public void startElement(NodeName elemName, SchemaType type,
AttributeMap attributes, NamespaceMap namespaces,
Location location, int properties) throws XPathException {
flush();
String qname = elemName.getDisplayName();
NamespaceUri uri = elemName.getNamespaceUri();
Element element;
if (ancestors.isEmpty()) {
startDocument(ReceiverOption.NONE);
implicitDocumentNode = true;
}
if (ancestors.size() == 1) {
element = nodeFactory.makeRootElement(qname, uri.toString());
document.setRootElement(element);
// At this point, any other children of the document node must be reinserted before the root element
int c = document.getChildCount();
if (c > 1) {
List otherChildren = new ArrayList(c);
for (int i=1; i