Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java StAX: pull XML events under a count and entity policy

Last updated: 5 Oct 20265 min read
tutorial
AdvancedBy AITrove Editorial

StAX lets the caller pull XML events one at a time. That limits retained tree state, but the caller still owns input size, entity policy, event count, and reader closure.

Operational contract

The factory disables DTD support and external entities, then the code counts receipt start elements. It rejects more than 47 receipts and closes the XMLStreamReader in finally. The source is a bounded byte array, so this method does not open an external stream. A provider may reject a requested property; fail that setup rather than ignoring it. Pull parsing is useful when the workflow needs only selected values, but an XML grammar and depth limit remain separate requirements. If an InputStream were supplied by a caller, closing the reader would not be a safe substitute for an explicit stream-ownership agreement.

Failure case

A depot accepts a manifest with 47 receipt elements. A 48th makes the document invalid for this intake, even if the XML is syntactically sound. The count is a business limit, not a parser feature. The implementation does not keep the document tree merely to compute that count.

Java code

Java
import java.io.ByteArrayInputStream;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;

public class ReceiptStaxCounter {
    public static int count(byte[] xml) throws Exception {
        if (xml.length > 47_000) throw new IllegalArgumentException("XML exceeds cap");
        XMLInputFactory factory = XMLInputFactory.newFactory();
        factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
        factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
        XMLStreamReader reader = factory.createXMLStreamReader(new ByteArrayInputStream(xml));
        try {
            int receipts = 0;
            while (reader.hasNext()) {
                if (reader.next() == XMLStreamConstants.START_ELEMENT
                        && "receipt".equals(reader.getLocalName())) {
                    if (++receipts > 47) throw new IllegalArgumentException("Too many receipts");
                }
            }
            return receipts;
        } finally {
            reader.close();
        }
    }
}

Performance and ownership cost

The scan is O(E) over E XML events and retains O(1) application state beyond parser buffers. The 47,000-byte input cap bounds the source array, while parser internals and deeply nested input still merit separate limits.

Common Mistakes

  • Do not assume streaming removes the need for input and depth caps.
  • Do not ignore a provider's refusal to disable external entities.
  • Do not leave the XMLStreamReader open after a failure.

Connected lessons

java
xml processing boundaries
xml-stax-pull-and-close
Storage details