diff --git a/core/src/java/org/jdom2/input/DefaultStAXFilter.java b/core/src/java/org/jdom2/input/DefaultStAXFilter.java new file mode 100644 index 000000000..e2aedbfe8 --- /dev/null +++ b/core/src/java/org/jdom2/input/DefaultStAXFilter.java @@ -0,0 +1,81 @@ +package org.jdom2.input; + +import org.jdom2.Namespace; + +/** + * This DefaultStAXFilter includes all content and prunes nothing. + *

+ * Override this class to make adjustments to get the results you need. + * + * @see StAXFilter + * + * @author Rolf Lear + */ +public class DefaultStAXFilter implements StAXFilter { + + @Override + public boolean includeDocType() { + return true; + } + + @Override + public boolean includeElement(final int depth, final String name, final Namespace ns) { + return true; + } + + @Override + public String includeComment(final int depth, final String comment) { + return comment; + } + + @Override + public boolean includeEntityRef(final int depth, final String name) { + return true; + } + + @Override + public String includeCDATA(final int depth, final String text) { + return text; + } + + @Override + public String includeText(final int depth, final String text) { + return text; + } + + @Override + public boolean includeProcessingInstruction(final int depth, final String target) { + return true; + } + + @Override + public boolean pruneElement(final int depth, final String name, final Namespace ns) { + return false; + } + + @Override + public String pruneComment(final int depth, final String comment) { + return comment; + } + + @Override + public boolean pruneEntityRef(final int depth, final String name) { + return false; + } + + @Override + public String pruneCDATA(final int depth, final String text) { + return text; + } + + @Override + public String pruneText(final int depth, final String text) { + return text; + } + + @Override + public boolean pruneProcessingInstruction(final int depth, final String target) { + return false; + } + +} diff --git a/core/src/java/org/jdom2/input/StAXFilter.java b/core/src/java/org/jdom2/input/StAXFilter.java new file mode 100644 index 000000000..4b7739276 --- /dev/null +++ b/core/src/java/org/jdom2/input/StAXFilter.java @@ -0,0 +1,243 @@ +package org.jdom2.input; + +import org.jdom2.Namespace; + +/** + * In StAX Processing it is possible to read fragments of XML. JDOM supports + * reading JDOM Content from StAX Readers in fragments. JDOM users can influence + * the content that is processed by the return values in this interface. + *

+ * Using the StAXStreamBuilder or StAXEventBuilder you can parse a List of + * JDOM content by filtering that content with an instance of this filter. + *

+ * There are two significant states in which methods in this interface will be + * called: + *

+ * + * @author Rolf Lear + * + */ +public interface StAXFilter { + + /** + * The current event is a DocType event. + * @return true if the DocType should become a JDOM Fragment. + */ + public boolean includeDocType(); + + /** + * The current event is an Element event. + *

+ * If the return value of this call is true, then this Element will be + * processed as a JDOM fragment. You may then get calls to the prune* + * methods to determine whether child content of this Element should be + * pruned + * @param depth The depth of this content from the document root + * (the root Element is at depth 0) + * @param name The XML tag name of this Element + * @param ns The Namespace of this Element + * @return true if the Element should become a JDOM Fragment. + */ + public boolean includeElement(int depth, String name, Namespace ns); + + /** + * The current event is a Comment event. + *

+ * A non-null return value will become the Comment text. Return null to skip + * the comment, the specified comment text to leave the comment unchanged, + * or any other String to create a different comment value. + *

+ * To include the comment as-is, do: + *
+ *

+	 * public String includeComment(int depth, String comment) {
+	 *     return comment;
+	 * }
+	 * 
+ * @param depth The depth of this content from the document root + * (the root Element is at depth 0) + * @param comment The Comment value + * @return null if you want to exclude this comment, or a non-null value + * which will become the new comment value. + */ + public String includeComment(int depth, String comment); + + /** + * The current event is an EntityRef event. + *

+ * @param depth The depth of this content from the document root + * (the root Element is at depth 0) + * @param name The EntityRef name + * @return true if you want to include this EntityRef. + */ + public boolean includeEntityRef(int depth, String name); + + /** + * The current event is a CDATA event. + *

+ * A non-null return value will become the CDATA text. Return null to skip + * the CDATA, the specified text to leave the CDATA unchanged, + * or any other String to create a different CDATA value. + *

+ * To include the CDATA as-is, do: + *
+ *

+	 * public String includeCDATA(int depth, String text) {
+	 *     return text;
+	 * }
+	 * 
+ * @param depth The depth of this content from the document root + * (the root Element is at depth 0) + * @param text The CDATA text value + * @return null if you want to exclude this CDATA, or a non-null value + * which will become the new CDATA text value. + */ + public String includeCDATA(int depth, String text); + + /** + * The current event is a TEXT event. + *

+ * A non-null return value will become the Text text. Return null to skip + * the Text, the specified text to leave the Text unchanged, + * or any other String to create a different Text value. + *

+ * To include the Text as-is, do: + *
+ *

+	 * public String includeText(int depth, String text) {
+	 *     return text;
+	 * }
+	 * 
+ * @param depth The depth of this content from the document root + * (the root Element is at depth 0) + * @param text The Text value + * @return null if you want to exclude this Text, or a non-null value + * which will become the new Text value. + */ + public String includeText(int depth, String text); + + /** + * The current event is a ProcessingInstruction event. + *

+ * @param depth The depth of this content from the document root + * (the root Element is at depth 0) + * @param target The ProcessingInstruction Target value + * @return true if you want to include this ProcessingInstruction. + */ + public boolean includeProcessingInstruction(int depth, String target); + + /** + * An Element is being included, and this is a child Element event of the + * included parent Element. Should this Child Element be pruned from the + * parent fragment? + * @param depth The depth of this content from the document root + * (the root Element is at depth 0) + * @param name The XML tag name of this child Element + * @param ns The Namespace of this child Element + * @return true if the child Element should be excluded. + */ + public boolean pruneElement(int depth, String name, Namespace ns); + + + /** + * An Element is being included, and this is a child Comment event of the + * included parent Element. Should this child Comment be pruned from the + * parent fragment? + *

+ * A non-null return value will become the Comment value. Return null to + * skip the Coment, the specified comment to leave the Comment unchanged, + * or any other String to create a different Comment value. + *

+ * To include the Comment as-is, do: + *
+ *

+	 * public String pruneComment(int depth, String comment) {
+	 *     return comment;
+	 * }
+	 * 
+ * @param depth The depth of this content from the document root + * (the root Element is at depth 0) + * @param comment The Comment value + * @return null if you want to exclude this Comment, or a non-null value + * which will become the new Comment value. + */ + public String pruneComment(int depth, String comment); + + /** + * An Element is being included, and this is a child EntityRef event of the + * included parent Element. Should this child EntityRef be pruned from the + * parent fragment? + *

+ * @param depth The depth of this content from the document root + * (the root Element is at depth 0) + * @param name The EntityRef name + * @return true if you want to exclude this EntityRef. + */ + public boolean pruneEntityRef(int depth, String name); + + /** + * An Element is being included, and this is a child CDATA event of the + * included parent Element. Should this child CDATA be pruned from the + * parent fragment? + *

+ * A non-null return value will become the CDATA text. Return null to skip + * the CDATA, the specified text to leave the CDATA unchanged, + * or any other String to create a different CDATA value. + *

+ * To include the CDATA as-is, do: + *
+ *

+	 * public String pruneCDATA(int depth, String text) {
+	 *     return text;
+	 * }
+	 * 
+ * @param depth The depth of this content from the document root + * (the root Element is at depth 0) + * @param text The CDATA text value + * @return null if you want to exclude this CDATA, or a non-null value + * which will become the new CDATA text value. + */ + public String pruneCDATA(int depth, String text); + + /** + * An Element is being included, and this is a child Text event of the + * included parent Element. Should this child Text be pruned from the + * parent fragment? + *

+ * A non-null return value will become the Text. Return null to skip + * the Text, the specified text to leave the Text unchanged, + * or any other String to create a different Text value. + *

+ * To include the Text as-is, do: + *
+ *

+	 * public String pruneText(int depth, String text) {
+	 *     return text;
+	 * }
+	 * 
+ * @param depth The depth of this content from the document root + * (the root Element is at depth 0) + * @param text The Text value + * @return null if you want to exclude this Text, or a non-null value + * which will become the new Text value. + */ + public String pruneText(int depth, String text); + + /** + * An Element is being included, and this is a child ProcessingInstruction + * event of the included parent Element. Should this ProcessingInstruction + * be pruned from the parent fragment? + *

+ * @param depth The depth of this content from the document root + * (the root Element is at depth 0) + * @param target The ProcessingInstruction Target value + * @return true if you want to exclude this ProcessingInstruction. + */ + public boolean pruneProcessingInstruction(int depth, String target); + +} diff --git a/core/src/java/org/jdom2/input/StAXStreamBuilder.java b/core/src/java/org/jdom2/input/StAXStreamBuilder.java index 72af8ba5a..660625c3d 100644 --- a/core/src/java/org/jdom2/input/StAXStreamBuilder.java +++ b/core/src/java/org/jdom2/input/StAXStreamBuilder.java @@ -54,11 +54,16 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT package org.jdom2.input; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import org.jdom2.AttributeType; +import org.jdom2.Content; import org.jdom2.DefaultJDOMFactory; import org.jdom2.DocType; import org.jdom2.Document; @@ -101,7 +106,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * */ public class StAXStreamBuilder implements XMLStreamConstants { - + /** * Create a Document from an XMLStreamReader * @param factory The {@link JDOMFactory} to use @@ -114,10 +119,6 @@ private static final Document process(final JDOMFactory factory, final XMLStreamReader stream) throws JDOMException { try { - final Document document = factory.document(null); - - Element current = null; - int state = stream.getEventType(); if (XMLStreamConstants.START_DOCUMENT != state) { @@ -125,6 +126,8 @@ private static final Document process(final JDOMFactory factory, "are at their beginning when being processed."); } + final Document document = factory.document(null); + while (state != XMLStreamConstants.END_DOCUMENT) { switch (state) { @@ -139,7 +142,7 @@ private static final Document process(final JDOMFactory factory, document.setProperty("ENCODING", stream.getEncoding()); break; - + case DTD: final DocType dtype = DTDParser.parse( stream.getText(), factory); @@ -147,79 +150,347 @@ private static final Document process(final JDOMFactory factory, break; case START_ELEMENT: - final Element emt = processElement(factory, stream); - if (current == null) { - document.setRootElement(emt); - final DocType dt = document.getDocType(); - if (dt != null) { - dt.setElementName(emt.getName()); - } + document.setRootElement(processElementFragment(factory, stream)); + break; + + case END_ELEMENT: + throw new JDOMException("Unexpected XMLStream event at Document level: END_ELEMENT"); + case ENTITY_REFERENCE: + throw new JDOMException("Unexpected XMLStream event at Document level: ENTITY_REFERENCE"); + case CDATA: + throw new JDOMException("Unexpected XMLStream event at Document level: CDATA"); + case SPACE: + throw new JDOMException("Unexpected XMLStream event at Document level: SPACE"); + case CHARACTERS: + throw new JDOMException("Unexpected XMLStream event at Document level: CHARACTERS"); + + case COMMENT: + document.addContent( + factory.comment(stream.getText())); + break; + + case PROCESSING_INSTRUCTION: + document.addContent(factory.processingInstruction( + stream.getPITarget(), stream.getPIData())); + break; + + default: + throw new JDOMException("Unexpected XMLStream event " + state); + + } + if (stream.hasNext()) { + state = stream.next(); + } else { + throw new JDOMException("Unexpected end-of-XMLStreamReader"); + } + } + return document; + } catch (final XMLStreamException xse) { + throw new JDOMException("Unable to process XMLStream. See Cause.", xse); + } + } + + private List processFragments(JDOMFactory factory, XMLStreamReader stream, StAXFilter filter) throws JDOMException { + + int state = stream.getEventType(); + + if (XMLStreamConstants.START_DOCUMENT != state) { + throw new JDOMException("JDOM requires that XMLStreamReaders " + + "are at their beginning when being processed."); + } + List ret = new ArrayList(); + + int depth = 0; + String text = null; + + try { + while (stream.hasNext() && (state = stream.next()) != END_DOCUMENT) { + switch (state) { + case START_DOCUMENT: + throw new JDOMException("Illegal state for XMLStreamReader. Cannot get XML Fragment for state START_DOCUMENT" ); + case END_DOCUMENT: + throw new JDOMException("Illegal state for XMLStreamReader. Cannot get XML Fragment for state END_DOCUMENT" ); + case END_ELEMENT: + throw new JDOMException("Illegal state for XMLStreamReader. Cannot get XML Fragment for state END_ELEMENT" ); + + case START_ELEMENT: + final QName qn = stream.getName(); + if (filter.includeElement(depth, qn.getLocalPart(), + Namespace.getNamespace(qn.getPrefix(), qn.getNamespaceURI()))) { + ret.add(processPrunableElement(factory, stream, depth, filter)); } else { - current.addContent(emt); + final int back = depth; + depth++; + + while (depth > back && stream.hasNext()) { + state = stream.next(); + if (state == START_ELEMENT) { + depth++; + } else if (state == END_ELEMENT) { + depth--; + } + } } - current = emt; break; - case END_ELEMENT: - current = current.getParentElement(); + case DTD: + if (filter.includeDocType()) { + ret.add(DTDParser.parse(stream.getText(), factory)); + } break; case CDATA: - if (current != null) { - current.addContent(factory.cdata(stream.getText())); + if ((text = filter.includeCDATA(depth, stream.getText())) != null) { + ret.add(factory.cdata(text)); } break; case SPACE: case CHARACTERS: - if (current != null) { - current.addContent(factory.text(stream.getText())); + if ((text = filter.includeText(depth, stream.getText())) != null) { + ret.add(factory.text(text)); } break; case COMMENT: - if (current == null) { - document.addContent( - factory.comment(stream.getText())); - } else { - current.addContent( - factory.comment(stream.getText())); + if ((text = filter.includeComment(depth, stream.getText())) != null) { + ret.add(factory.comment(text)); } break; case ENTITY_REFERENCE: - if (current != null) { - current.addContent( - factory.entityRef(stream.getLocalName())); + if (filter.includeEntityRef(depth, stream.getLocalName())) { + ret.add(factory.entityRef(stream.getLocalName())); } break; case PROCESSING_INSTRUCTION: - if (current == null) { - document.addContent(factory.processingInstruction( - stream.getPITarget(), stream.getPIData())); - } else { - current.addContent(factory.processingInstruction( - stream.getPITarget(), stream.getPIData())); + if (filter.includeProcessingInstruction(depth, stream.getPITarget())) { + ret.add(factory.processingInstruction( + stream.getPITarget(), stream.getPIData())); } break; default: - throw new JDOMException("Unexpected XMLStream event " + state); - - } - if (stream.hasNext()) { - state = stream.next(); - } else { - throw new JDOMException("Unexpected end-of-XMLStreamReader"); + throw new JDOMException("Unexpected XMLStream event " + stream.getEventType()); } } - return document; + } catch (XMLStreamException e) { + throw new JDOMException("Unable to process fragments from XMLStreamReader.", e); + } + + return ret; + } + + + private static final Element processPrunableElement(final JDOMFactory factory, + final XMLStreamReader reader, final int topdepth, StAXFilter filter) + throws XMLStreamException, JDOMException { + + if (XMLStreamConstants.START_ELEMENT != reader.getEventType()) { + throw new JDOMException("JDOM requires that the XMLStreamReader " + + "is at the START_ELEMENT state when retrieving an " + + "Element Fragment."); + } + + final Element fragment = processElement(factory, reader); + Element current = fragment; + int depth = topdepth + 1; + String text = null; + while (depth > topdepth && reader.hasNext()) { + switch(reader.next()) { + case START_ELEMENT: + QName qn = reader.getName(); + if (!filter.pruneElement(depth, qn.getLocalPart(), + Namespace.getNamespace( + qn.getPrefix(), qn.getNamespaceURI()))) { + Element tmp = processElement(factory, reader); + current.addContent(tmp); + current = tmp; + depth++; + } else { + final int edepth = depth; + depth++; + int state = 0; + while (depth > edepth && reader.hasNext() && + (state = reader.next()) != END_DOCUMENT) { + if (state == START_ELEMENT) { + depth++; + } else if (state == END_ELEMENT) { + depth--; + } + } + } + break; + case END_ELEMENT: + current = current.getParentElement(); + depth--; + break; + case CDATA: + if ((text = filter.pruneCDATA(depth, reader.getText())) != null) { + current.addContent(factory.cdata(text)); + } + break; + + case SPACE: + case CHARACTERS: + if ((text = filter.pruneText(depth, reader.getText())) != null) { + current.addContent(factory.text(text)); + } + break; + + case COMMENT: + if ((text = filter.pruneComment(depth, reader.getText())) != null) { + current.addContent(factory.comment(text)); + } + break; + + case ENTITY_REFERENCE: + if (!filter.pruneEntityRef(depth, reader.getLocalName())) { + current.addContent(factory.entityRef(reader.getLocalName())); + } + break; + + case PROCESSING_INSTRUCTION: + if (!filter.pruneProcessingInstruction(depth, reader.getPITarget())) { + current.addContent(factory.processingInstruction( + reader.getPITarget(), reader.getPIData())); + } + break; + + default: + throw new JDOMException("Unexpected XMLStream event " + reader.getEventType()); + } + + } + + return fragment; + } + + /** + * Create a Content from an XMLStreamReader + * The stream is advanced to the event after the current event (or to the + * event after the matching END_ELEMENT for an Element fragment). + * @param factory The {@link JDOMFactory} to use + * @param stream The XMLStreamReader to read from + * @return the parsed Document + * @throws JDOMException if there is any issue + * (XMLStreamExceptions are wrapped). + */ + private static final Content processFragment(final JDOMFactory factory, + final XMLStreamReader stream) throws JDOMException { + try { + + switch (stream.getEventType()) { + + case START_DOCUMENT: + throw new JDOMException("Illegal state for XMLStreamReader. Cannot get XML Fragment for state START_DOCUMENT" ); + case END_DOCUMENT: + throw new JDOMException("Illegal state for XMLStreamReader. Cannot get XML Fragment for state END_DOCUMENT" ); + case END_ELEMENT: + throw new JDOMException("Illegal state for XMLStreamReader. Cannot get XML Fragment for state END_ELEMENT" ); + + case START_ELEMENT: + Element emt = processElementFragment(factory, stream); + stream.next(); + return emt; + + case DTD: + Content dt = DTDParser.parse(stream.getText(), factory); + stream.next(); + return dt; + + case CDATA: + Content cd = factory.cdata(stream.getText()); + stream.next(); + return cd; + + case SPACE: + case CHARACTERS: + Content txt = factory.text(stream.getText()); + stream.next(); + return txt; + + case COMMENT: + Content comment = factory.comment(stream.getText()); + stream.next(); + return comment; + + case ENTITY_REFERENCE: + Content er = factory.entityRef(stream.getLocalName()); + stream.next(); + return er; + + case PROCESSING_INSTRUCTION: + Content pi = factory.processingInstruction( + stream.getPITarget(), stream.getPIData()); + stream.next(); + return pi; + + default: + throw new JDOMException("Unexpected XMLStream event " + stream.getEventType()); + + } } catch (final XMLStreamException xse) { throw new JDOMException("Unable to process XMLStream. See Cause.", xse); } } + private static final Element processElementFragment(final JDOMFactory factory, + final XMLStreamReader reader) throws XMLStreamException, JDOMException { + + if (XMLStreamConstants.START_ELEMENT != reader.getEventType()) { + throw new JDOMException("JDOM requires that the XMLStreamReader " + + "is at the START_ELEMENT state when retrieving an " + + "Element Fragment."); + } + + final Element fragment = processElement(factory, reader); + Element current = fragment; + int depth = 1; + while (depth > 0 && reader.hasNext()) { + switch(reader.next()) { + case START_ELEMENT: + Element tmp = processElement(factory, reader); + current.addContent(tmp); + current = tmp; + depth++; + break; + case END_ELEMENT: + current = current.getParentElement(); + depth--; + break; + case CDATA: + current.addContent(factory.cdata(reader.getText())); + break; + + case SPACE: + case CHARACTERS: + current.addContent(factory.text(reader.getText())); + break; + + case COMMENT: + current.addContent(factory.comment(reader.getText())); + break; + + case ENTITY_REFERENCE: + current.addContent(factory.entityRef(reader.getLocalName())); + break; + + case PROCESSING_INSTRUCTION: + current.addContent(factory.processingInstruction( + reader.getPITarget(), reader.getPIData())); + break; + + default: + throw new JDOMException("Unexpected XMLStream event " + reader.getEventType()); + } + + } + + return fragment; + } + private static final Element processElement(final JDOMFactory factory, final XMLStreamReader reader) { @@ -234,7 +505,7 @@ private static final Element processElement(final JDOMFactory factory, reader.getAttributeValue(i), AttributeType.getAttributeType(reader.getAttributeType(i)), Namespace.getNamespace(reader.getAttributePrefix(i), - reader.getAttributeNamespace(i)))); + reader.getAttributeNamespace(i)))); } // Handle Namespaces @@ -248,14 +519,14 @@ private static final Element processElement(final JDOMFactory factory, /** The factory to use for parsing */ - private JDOMFactory factory = new DefaultJDOMFactory(); - + private JDOMFactory builderfactory = new DefaultJDOMFactory(); + /** * Returns the current {@link org.jdom2.JDOMFactory} in use. * @return the factory in use */ public JDOMFactory getFactory() { - return factory; + return builderfactory; } /** @@ -265,9 +536,9 @@ public JDOMFactory getFactory() { * @param factory JDOMFactory to use */ public void setFactory(JDOMFactory factory) { - this.factory = factory; + this.builderfactory = factory; } - + /** * This builds a document from the supplied * XMLStreamReader. @@ -279,7 +550,33 @@ public void setFactory(JDOMFactory factory) { * @throws JDOMException when errors occur in parsing */ public Document build(XMLStreamReader reader) throws JDOMException { - return process(factory, reader); + return process(builderfactory, reader); + } + + /** + * Read the entire XMLStreamReader and from it build a list of Content that + * conforms to the rules in the supplied StAXFilter. + * @param reader The XMLStreamReader to parse + * @param filter The Filter to use for the Content + * @return a List of Content that were identified by the supplied filter + * @throws JDOMException if there was a parsing problem. + */ + public List buildFragments(XMLStreamReader reader, StAXFilter filter) throws JDOMException { + return processFragments(builderfactory, reader, filter); } + + /** + * Read the current XML Fragment from the XMLStreamReader. + * The XMLStreamReader must be at some 'content' state, it cannot be + * at START_DOCUMENT, for example. + * @param reader The XMLStreamReader to read the next fragment from + * @return The JDOM fragment at the current position in the reader + * @throws JDOMException if there is an issue with the state of the + * XMLStreamReader or some other issue with the processing. + */ + public Content fragment(XMLStreamReader reader) throws JDOMException { + return processFragment(builderfactory, reader); + } + } diff --git a/test/src/java/org/jdom2/test/cases/input/TestStAXBuilder.java b/test/src/java/org/jdom2/test/cases/input/TestStAXBuilder.java index 02cde4560..728535759 100644 --- a/test/src/java/org/jdom2/test/cases/input/TestStAXBuilder.java +++ b/test/src/java/org/jdom2/test/cases/input/TestStAXBuilder.java @@ -9,12 +9,14 @@ import java.io.CharArrayWriter; import java.io.File; import java.io.IOException; +import java.util.List; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; import javax.xml.transform.stream.StreamSource; import org.jdom2.*; +import org.jdom2.input.DefaultStAXFilter; import org.jdom2.input.SAXBuilder; import org.jdom2.input.StAXStreamBuilder; import org.jdom2.output.Format; @@ -114,6 +116,12 @@ private void checkStAX(String filename, boolean expand) { XMLStreamReader reader = inputfac.createXMLStreamReader(source); Document staxbuild = stxb.build(reader); Element staxroot = staxbuild.hasRootElement() ? staxbuild.getRootElement() : null; + + XMLStreamReader fragreader = inputfac.createXMLStreamReader(source); + List contentlist = stxb.buildFragments(fragreader, new DefaultStAXFilter()); + Document fragbuild = new Document(); + fragbuild.addContent(contentlist); + Element fragroot = fragbuild.getRootElement(); SAXBuilder sb = new SAXBuilder(false); sb.setExpandEntities(expand); @@ -125,6 +133,8 @@ private void checkStAX(String filename, boolean expand) { assertEquals("DOC SAX to StAXReader", toString(saxbuild), toString(staxbuild)); assertEquals("ROOT SAX to StAXReader", toString(saxroot), toString(staxroot)); + assertEquals("DOC SAX to StAXReader FragmentList", toString(saxbuild), toString(fragbuild)); + assertEquals("ROOT SAX to StAXReader FragmentList", toString(saxroot), toString(fragroot)); } catch (Exception e) { e.printStackTrace();