Switching to use CXF's StaxUtils for DOM parsing. Still having problems with DTD parsing.

git-svn-id: https://svn.apache.org/repos/asf/santuario/xml-security-java/branches/staxutils@1847262 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java b/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java
index 17c60de..7565799 100644
--- a/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java
+++ b/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java
@@ -26,6 +26,8 @@
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+import javax.xml.stream.XMLStreamException;
+
 import org.apache.xml.security.c14n.implementations.Canonicalizer11_OmitComments;
 import org.apache.xml.security.c14n.implementations.Canonicalizer11_WithComments;
 import org.apache.xml.security.c14n.implementations.Canonicalizer20010315ExclOmitComments;
@@ -246,10 +248,11 @@
      * @throws java.io.IOException
      * @throws javax.xml.parsers.ParserConfigurationException
      * @throws org.xml.sax.SAXException
+     * @throws XMLStreamException
      */
     public byte[] canonicalize(byte[] inputBytes)
         throws javax.xml.parsers.ParserConfigurationException,
-        java.io.IOException, org.xml.sax.SAXException, CanonicalizationException {
+        java.io.IOException, org.xml.sax.SAXException, CanonicalizationException, XMLStreamException {
         Document document = null;
         try (InputStream bais = new ByteArrayInputStream(inputBytes)) {
             InputSource in = new InputSource(bais);
diff --git a/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java b/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java
index be193eb..9734bb5 100644
--- a/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java
+++ b/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java
@@ -22,6 +22,8 @@
 import java.io.OutputStream;
 import java.util.Set;
 
+import javax.xml.stream.XMLStreamException;
+
 import org.apache.xml.security.utils.XMLUtils;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
@@ -48,10 +50,11 @@
      * @throws java.io.IOException
      * @throws javax.xml.parsers.ParserConfigurationException
      * @throws org.xml.sax.SAXException
+     * @throws XMLStreamException
      */
     public byte[] engineCanonicalize(byte[] inputBytes)
         throws javax.xml.parsers.ParserConfigurationException, java.io.IOException,
-        org.xml.sax.SAXException, CanonicalizationException {
+        org.xml.sax.SAXException, CanonicalizationException, XMLStreamException {
 
         Document document = null;
         try (java.io.InputStream bais = new ByteArrayInputStream(inputBytes)) {
diff --git a/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315.java b/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315.java
index 03c0548..954f640 100644
--- a/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315.java
+++ b/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315.java
@@ -26,6 +26,7 @@
 import java.util.TreeSet;
 
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
 
 import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.c14n.helper.C14nHelper;
@@ -296,7 +297,7 @@
     }
 
     protected void circumventBugIfNeeded(XMLSignatureInput input)
-        throws CanonicalizationException, ParserConfigurationException, IOException, SAXException {
+        throws CanonicalizationException, ParserConfigurationException, IOException, SAXException, XMLStreamException {
         if (!input.isNeedsToBeExpanded()) {
             return;
         }
diff --git a/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315Excl.java b/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315Excl.java
index fda565e..ef34f68 100644
--- a/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315Excl.java
+++ b/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315Excl.java
@@ -25,6 +25,7 @@
 import java.util.SortedSet;
 import java.util.TreeSet;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
 
 import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.c14n.helper.C14nHelper;
@@ -337,7 +338,7 @@
 
     protected void circumventBugIfNeeded(XMLSignatureInput input)
         throws CanonicalizationException, ParserConfigurationException,
-               IOException, SAXException {
+               IOException, SAXException, XMLStreamException {
         if (!input.isNeedsToBeExpanded() || inclusiveNSSet.isEmpty()) {
             return;
         }
diff --git a/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java b/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java
index 8a329cf..1bd60d4 100644
--- a/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java
+++ b/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java
@@ -31,6 +31,7 @@
 import java.util.Set;
 
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
 
 import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.c14n.CanonicalizerSpi;
@@ -160,11 +161,7 @@
                 }
             }
             return null;
-        } catch (ParserConfigurationException ex) {
-            throw new CanonicalizationException(ex);
-        } catch (IOException ex) {
-            throw new CanonicalizationException(ex);
-        } catch (SAXException ex) {
+        } catch (ParserConfigurationException | IOException | SAXException | XMLStreamException ex) {
             throw new CanonicalizationException(ex);
         }
     }
@@ -654,7 +651,7 @@
         throws CanonicalizationException, DOMException, IOException;
 
     abstract void circumventBugIfNeeded(XMLSignatureInput input)
-        throws CanonicalizationException, ParserConfigurationException, IOException, SAXException;
+        throws CanonicalizationException, ParserConfigurationException, IOException, SAXException, XMLStreamException;
 
     /**
      * Outputs an Attribute to the internal Writer.
diff --git a/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java b/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java
index a35ff71..4c17e8b 100644
--- a/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java
+++ b/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java
@@ -24,6 +24,7 @@
 import java.io.StringReader;
 
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
 
 import org.apache.xml.security.utils.XMLUtils;
 import org.w3c.dom.Document;
@@ -89,12 +90,8 @@
                 child = fragElt.getFirstChild();
             }
             return result;
-        } catch (SAXException se) {
-            throw new XMLEncryptionException(se);
-        } catch (ParserConfigurationException pce) {
-            throw new XMLEncryptionException(pce);
-        } catch (IOException ioe) {
-            throw new XMLEncryptionException(ioe);
+        } catch (ParserConfigurationException | IOException | SAXException | XMLStreamException ex) {
+            throw new XMLEncryptionException(ex);
         }
     }
 
diff --git a/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java b/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java
index f5456a6..f55243c 100644
--- a/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java
+++ b/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java
@@ -28,6 +28,7 @@
 
 import javax.crypto.SecretKey;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
 
 import org.apache.xml.security.keys.storage.StorageResolver;
 import org.apache.xml.security.utils.XMLUtils;
@@ -273,11 +274,7 @@
         try (InputStream is = new ByteArrayInputStream(bytes)) {
             Document doc = XMLUtils.read(is, secureValidation);
             return doc.getDocumentElement();
-        } catch (SAXException ex) {
-            throw new KeyResolverException(ex);
-        } catch (IOException ex) {
-            throw new KeyResolverException(ex);
-        } catch (ParserConfigurationException ex) {
+        } catch (ParserConfigurationException | IOException | SAXException | XMLStreamException ex) {
             throw new KeyResolverException(ex);
         }
     }
diff --git a/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java b/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java
index 611e494..7f557f9 100644
--- a/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java
+++ b/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java
@@ -32,6 +32,7 @@
 import java.util.Set;
 
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
 
 import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.exceptions.XMLSecurityException;
@@ -126,7 +127,9 @@
              LOG.debug("ParserConfigurationException", e);
          } catch (SAXException e) {
              LOG.debug("SAXException", e);
-         }
+         } catch (XMLStreamException e) {
+             LOG.debug("XMLStreamException", e);
+        }
          return null;
     }
 
@@ -184,6 +187,8 @@
             LOG.debug("ParserConfigurationException", e);
         } catch (SAXException e) {
             LOG.debug("SAXException", e);
+        } catch (XMLStreamException e) {
+            LOG.debug("XMLStreamException", e);
         }
         return null;
     }
@@ -234,7 +239,7 @@
 
     private static Element obtainReferenceElement(XMLSignatureInput resource, boolean secureValidation)
         throws CanonicalizationException, ParserConfigurationException,
-        IOException, SAXException, KeyResolverException {
+        IOException, SAXException, KeyResolverException, XMLStreamException {
         Element e;
         if (resource.isElement()){
             e = (Element) resource.getSubNode();
diff --git a/src/main/java/org/apache/xml/security/signature/Manifest.java b/src/main/java/org/apache/xml/security/signature/Manifest.java
index 7eb83e5..240d93f 100644
--- a/src/main/java/org/apache/xml/security/signature/Manifest.java
+++ b/src/main/java/org/apache/xml/security/signature/Manifest.java
@@ -30,6 +30,7 @@
 import java.util.Set;
 
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
 
 import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.c14n.InvalidCanonicalizerException;
@@ -399,11 +400,7 @@
                         }
 
                         manifestReferences = referencedManifest.getVerificationResults();
-                    } catch (IOException ex) {
-                        throw new ReferenceNotInitializedException(ex);
-                    } catch (ParserConfigurationException ex) {
-                        throw new ReferenceNotInitializedException(ex);
-                    } catch (SAXException ex) {
+                    } catch (ParserConfigurationException | IOException | SAXException | XMLStreamException ex) {
                         throw new ReferenceNotInitializedException(ex);
                     }
                 }
diff --git a/src/main/java/org/apache/xml/security/signature/SignedInfo.java b/src/main/java/org/apache/xml/security/signature/SignedInfo.java
index 28b553d..aa46878 100644
--- a/src/main/java/org/apache/xml/security/signature/SignedInfo.java
+++ b/src/main/java/org/apache/xml/security/signature/SignedInfo.java
@@ -26,6 +26,7 @@
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
 
 import org.apache.xml.security.algorithms.SignatureAlgorithm;
 import org.apache.xml.security.c14n.CanonicalizationException;
@@ -218,11 +219,7 @@
                     element.getParentNode().replaceChild(imported, element);
                     return (Element) imported;
                 }
-            } catch (ParserConfigurationException ex) {
-                throw new XMLSecurityException(ex);
-            } catch (IOException ex) {
-                throw new XMLSecurityException(ex);
-            } catch (SAXException ex) {
+            } catch (ParserConfigurationException | IOException | SAXException | XMLStreamException ex) {
                 throw new XMLSecurityException(ex);
             }
         }
diff --git a/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java b/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java
index e8f82fa..b8ba860 100644
--- a/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java
+++ b/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java
@@ -30,6 +30,7 @@
 import java.util.Set;
 
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
 
 import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.c14n.implementations.Canonicalizer11_OmitComments;
@@ -191,9 +192,10 @@
      * @throws IOException
      * @throws ParserConfigurationException
      * @throws CanonicalizationException
+     * @throws XMLStreamException
      */
     public Set<Node> getNodeSet() throws CanonicalizationException, ParserConfigurationException,
-        IOException, SAXException {
+        IOException, SAXException, XMLStreamException {
         return getNodeSet(false);
     }
 
@@ -215,9 +217,10 @@
      * @throws IOException
      * @throws ParserConfigurationException
      * @throws CanonicalizationException
+     * @throws XMLStreamException
      */
     public Set<Node> getNodeSet(boolean circumvent) throws ParserConfigurationException,
-        IOException, SAXException, CanonicalizationException {
+        IOException, SAXException, CanonicalizationException, XMLStreamException {
         if (inputNodeSet != null) {
             return inputNodeSet;
         }
@@ -568,7 +571,7 @@
     }
 
     void convertToNodes() throws CanonicalizationException,
-        ParserConfigurationException, IOException, SAXException {
+        ParserConfigurationException, IOException, SAXException, XMLStreamException {
         // select all nodes, also the comments.
         try {
             Document doc = XMLUtils.read(this.getOctetStream(), secureValidation);
diff --git a/src/main/java/org/apache/xml/security/staxutils/AbstractDOMStreamReader.java b/src/main/java/org/apache/xml/security/staxutils/AbstractDOMStreamReader.java
new file mode 100644
index 0000000..9484c89
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/AbstractDOMStreamReader.java
@@ -0,0 +1,361 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.staxutils;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+
+/**
+ * Abstract logic for creating XMLStreamReader from DOM documents. Its works
+ * using adapters for Element, Node and Attribute.
+ */
+public abstract class AbstractDOMStreamReader<T, I> implements XMLStreamReader {
+    protected int currentEvent = XMLStreamConstants.START_DOCUMENT;
+
+    private FastStack<ElementFrame<T, I>> frames = new FastStack<>();
+
+    private ElementFrame<T, I> frame;
+
+
+    /**
+     *
+     */
+    public static class ElementFrame<T, I> {
+        T element;
+        I currentChild;
+
+        boolean started;
+        boolean ended;
+
+        List<String> uris;
+        List<String> prefixes;
+        List<Object> attributes;
+
+        final ElementFrame<T, I> parent;
+
+        public ElementFrame(T element, ElementFrame<T, I> parent) {
+            this.element = element;
+            this.parent = parent;
+        }
+
+        public ElementFrame(T element, ElementFrame<T, I> parent, I ch) {
+            this.element = element;
+            this.parent = parent;
+            this.currentChild = ch;
+        }
+        public ElementFrame(T doc, boolean s) {
+            this.element = doc;
+            parent = null;
+            started = s;
+            attributes = Collections.emptyList();
+            prefixes = Collections.emptyList();
+            uris = Collections.emptyList();
+        }
+        public ElementFrame(T doc) {
+            this(doc, true);
+        }
+        public T getElement() {
+            return element;
+        }
+
+        public I getCurrentChild() {
+            return currentChild;
+        }
+        public void setCurrentChild(I o) {
+            currentChild = o;
+        }
+        public boolean isDocument() {
+            return false;
+        }
+        public boolean isDocumentFragment() {
+            return false;
+        }
+    }
+
+    /**
+     * @param frame
+     */
+    public AbstractDOMStreamReader(ElementFrame<T, I> frame) {
+        this.frame = frame;
+        frames.push(this.frame);
+    }
+
+    protected ElementFrame<T, I> getCurrentFrame() {
+        return frame;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.stream.XMLStreamReader#getProperty(java.lang.String)
+     */
+    public Object getProperty(String key) throws IllegalArgumentException {
+        return null;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.stream.XMLStreamReader#next()
+     */
+    public int next() throws XMLStreamException {
+        if (frame.ended) {
+            frames.pop();
+            if (!frames.empty()) {
+                frame = frames.peek();
+            } else {
+                currentEvent = END_DOCUMENT;
+                return currentEvent;
+            }
+        }
+
+        if (!frame.started) {
+            frame.started = true;
+            currentEvent = frame.isDocument() ? START_DOCUMENT : START_ELEMENT;
+        } else if (hasMoreChildren()) {
+            currentEvent = nextChild();
+
+            if (currentEvent == START_ELEMENT) {
+                ElementFrame<T, I> newFrame = getChildFrame();
+                newFrame.started = true;
+                frame = newFrame;
+                frames.push(this.frame);
+                currentEvent = START_ELEMENT;
+
+                newFrame(newFrame);
+            }
+        } else {
+            frame.ended = true;
+            if (frame.isDocument()) {
+                currentEvent = END_DOCUMENT;
+            } else {
+                currentEvent = END_ELEMENT;
+                endElement();
+            }
+        }
+        return currentEvent;
+    }
+
+    protected void newFrame(ElementFrame<T, I> newFrame) {
+    }
+
+    protected void endElement() {
+    }
+
+    protected abstract boolean hasMoreChildren();
+    protected abstract int nextChild();
+    protected abstract ElementFrame<T, I> getChildFrame();
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.stream.XMLStreamReader#require(int, java.lang.String,
+     *      java.lang.String)
+     */
+    public void require(int arg0, String arg1, String arg2) throws XMLStreamException {
+        throw new UnsupportedOperationException();
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.stream.XMLStreamReader#getElementText()
+     */
+    public abstract String getElementText() throws XMLStreamException;
+
+    public void consumeFrame() {
+        frame.started = true;
+        frame.ended = true;
+        if (frame.isDocument()) {
+            currentEvent = END_DOCUMENT;
+        } else {
+            currentEvent = END_ELEMENT;
+            endElement();
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.stream.XMLStreamReader#nextTag()
+     */
+    public int nextTag() throws XMLStreamException {
+        while (hasNext()) {
+            if (START_ELEMENT == next()) {
+                return START_ELEMENT;
+            }
+        }
+
+        return currentEvent;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.stream.XMLStreamReader#hasNext()
+     */
+    public boolean hasNext() throws XMLStreamException {
+
+        return !(frame.ended && (frames.isEmpty() || frame.isDocumentFragment()));
+
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.stream.XMLStreamReader#close()
+     */
+    public void close() throws XMLStreamException {
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.stream.XMLStreamReader#getNamespaceURI(java.lang.String)
+     */
+    public abstract String getNamespaceURI(String prefix);
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.stream.XMLStreamReader#isStartElement()
+     */
+    public boolean isStartElement() {
+        return currentEvent == START_ELEMENT;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.stream.XMLStreamReader#isEndElement()
+     */
+    public boolean isEndElement() {
+        return currentEvent == END_ELEMENT;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.stream.XMLStreamReader#isCharacters()
+     */
+    public boolean isCharacters() {
+        return currentEvent == CHARACTERS;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see javax.xml.stream.XMLStreamReader#isWhiteSpace()
+     */
+    public boolean isWhiteSpace() {
+        if (currentEvent == CHARACTERS || currentEvent == CDATA) {
+            String text = getText();
+            int len = text.length();
+            for (int i = 0; i < len; ++i) {
+                if (text.charAt(i) > 0x0020) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return currentEvent == SPACE;
+    }
+
+    public int getEventType() {
+        return currentEvent;
+    }
+
+    public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length)
+        throws XMLStreamException {
+        char[] src = getText().toCharArray();
+
+        if (sourceStart + length >= src.length) {
+            length = src.length - sourceStart;
+        }
+
+        for (int i = 0; i < length; i++) {
+            target[targetStart + i] = src[i + sourceStart];
+        }
+
+        return length;
+    }
+
+    public boolean hasText() {
+        return currentEvent == CHARACTERS || currentEvent == DTD || currentEvent == ENTITY_REFERENCE
+                || currentEvent == COMMENT || currentEvent == SPACE;
+    }
+
+    public String getSystemId() {
+        return null;
+    }
+    public String getPublicId() {
+        return null;
+    }
+    public Location getLocation() {
+        return new Location() {
+
+            public int getCharacterOffset() {
+                return 0;
+            }
+
+            public int getColumnNumber() {
+                return 0;
+            }
+
+            public int getLineNumber() {
+                return 0;
+            }
+
+            public String getPublicId() {
+                return AbstractDOMStreamReader.this.getPublicId();
+            }
+
+            public String getSystemId() {
+                return AbstractDOMStreamReader.this.getSystemId();
+            }
+
+        };
+    }
+
+    public boolean hasName() {
+        return currentEvent == START_ELEMENT || currentEvent == END_ELEMENT;
+    }
+
+    public String getVersion() {
+        return null;
+    }
+
+    public boolean isStandalone() {
+        return false;
+    }
+
+    public boolean standaloneSet() {
+        return false;
+    }
+
+    public String getCharacterEncodingScheme() {
+        return null;
+    }
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/DOMUtils.java b/src/main/java/org/apache/xml/security/staxutils/DOMUtils.java
new file mode 100644
index 0000000..a833a62
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/DOMUtils.java
@@ -0,0 +1,142 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.xml.security.staxutils;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+/**
+ * Few simple utils to read DOM. This is originally from the Jakarta Commons Modeler.
+ */
+public final class DOMUtils {
+    private static final Map<ClassLoader, DocumentBuilder> DOCUMENT_BUILDERS
+        = Collections.synchronizedMap(new WeakHashMap<ClassLoader, DocumentBuilder>());
+    private static final Map<ClassLoader, DocumentBuilder> DOCUMENT_BUILDERS_DISALLOW_DOCTYPE
+        = Collections.synchronizedMap(new WeakHashMap<ClassLoader, DocumentBuilder>());
+
+    private DOMUtils() {
+    }
+
+    private static DocumentBuilder getDocumentBuilder(boolean disAllowDocTypeDeclarations) throws ParserConfigurationException {
+        ClassLoader loader = getContextClassLoader();
+        if (loader == null) {
+            loader = getClassLoader(DOMUtils.class);
+        }
+        if (loader == null) {
+            DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
+            f.setNamespaceAware(true);
+            f.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
+            f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", disAllowDocTypeDeclarations);
+            return f.newDocumentBuilder();
+        }
+        DocumentBuilder factory =
+            disAllowDocTypeDeclarations ? DOCUMENT_BUILDERS_DISALLOW_DOCTYPE.get(loader) : DOCUMENT_BUILDERS.get(loader);
+        if (factory == null) {
+            DocumentBuilderFactory f2 = DocumentBuilderFactory.newInstance();
+            f2.setNamespaceAware(true);
+            f2.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
+            f2.setFeature("http://apache.org/xml/features/disallow-doctype-decl", disAllowDocTypeDeclarations);
+            factory = f2.newDocumentBuilder();
+            if (disAllowDocTypeDeclarations) {
+                DOCUMENT_BUILDERS_DISALLOW_DOCTYPE.put(loader, factory);
+            } else {
+                DOCUMENT_BUILDERS.put(loader, factory);
+            }
+        }
+        return factory;
+    }
+
+    private static ClassLoader getContextClassLoader() {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+                public ClassLoader run() {
+                    return Thread.currentThread().getContextClassLoader();
+                }
+            });
+        }
+        return Thread.currentThread().getContextClassLoader();
+    }
+
+    private static ClassLoader getClassLoader(final Class<?> clazz) {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+                public ClassLoader run() {
+                    return clazz.getClassLoader();
+                }
+            });
+        }
+        return clazz.getClassLoader();
+    }
+
+    /**
+     * Creates a new Document object
+     * @throws ParserConfigurationException
+     */
+    public static Document newDocument(boolean disAllowDocTypeDeclarations) {
+        try {
+            return getDocumentBuilder(disAllowDocTypeDeclarations).newDocument();
+        } catch (ParserConfigurationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Get the raw text content of a node or null if there is no text
+     */
+    public static String getRawContent(Node n) {
+        if (n == null) {
+            return null;
+        }
+        StringBuilder b = null;
+        String s = null;
+        Node n1 = n.getFirstChild();
+        while (n1 != null) {
+            if (n1.getNodeType() == Node.TEXT_NODE || n1.getNodeType() == Node.CDATA_SECTION_NODE) {
+                if (b != null) {
+                    b.append(((Text)n1).getNodeValue());
+                } else if (s == null) {
+                    s = ((Text)n1).getNodeValue();
+                } else {
+                    b = new StringBuilder(s).append(((Text)n1).getNodeValue());
+                    s = null;
+                }
+            }
+            n1 = n1.getNextSibling();
+        }
+        if (b != null) {
+            return b.toString();
+        }
+        return s;
+    }
+
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/DepthExceededStaxException.java b/src/main/java/org/apache/xml/security/staxutils/DepthExceededStaxException.java
new file mode 100644
index 0000000..5886a20
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/DepthExceededStaxException.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.staxutils;
+
+public class DepthExceededStaxException extends RuntimeException {
+
+    private static final long serialVersionUID = 4750070687283463619L;
+
+    public DepthExceededStaxException() {
+
+    }
+
+    public DepthExceededStaxException(String message) {
+        super(message);
+    }
+
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/DepthRestrictingStreamReader.java b/src/main/java/org/apache/xml/security/staxutils/DepthRestrictingStreamReader.java
new file mode 100644
index 0000000..6e493ae
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/DepthRestrictingStreamReader.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.staxutils;
+
+import java.util.Stack;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+/**
+ * XMLStreamReader implementation which can be used to enforce a number of
+ * depth-restricting policies. The following properties are currently supported:
+ * - total number of elements in the document
+ * - the maximum depth of the given element; the root element will be checked by default
+ * - the maximum number of immediate child nodes for individual elements
+ *
+ * More sophisticated policies can be supported in the future.
+ */
+public class DepthRestrictingStreamReader extends DepthXMLStreamReader {
+
+    private DocumentDepthProperties props;
+    private int totalElementCount;
+    private Stack<Integer> stack = new Stack<>();
+
+    public DepthRestrictingStreamReader(XMLStreamReader reader,
+                                        int elementCountThreshold,
+                                        int innerElementLevelThreshold,
+                                        int innerElementCountThreshold) {
+        this(reader, new DocumentDepthProperties(elementCountThreshold,
+                                                 innerElementLevelThreshold,
+                                                 innerElementCountThreshold));
+    }
+
+    public DepthRestrictingStreamReader(XMLStreamReader reader,
+                                        DocumentDepthProperties props) {
+        super(reader);
+        this.props = props;
+    }
+
+    @Override
+    public int next() throws XMLStreamException {
+        int next = super.next();
+        if (next == START_ELEMENT) {
+            if (props.getInnerElementLevelThreshold() != -1
+                && getDepth() >= props.getInnerElementLevelThreshold()) {
+                throw new DepthExceededStaxException();
+            }
+            if (props.getElementCountThreshold() != -1
+                && ++totalElementCount >= props.getElementCountThreshold()) {
+                throw new DepthExceededStaxException();
+            }
+            if (props.getInnerElementCountThreshold() != -1) {
+                if (!stack.empty()) {
+                    int currentCount = stack.pop();
+                    if (++currentCount >= props.getInnerElementCountThreshold()) {
+                        throw new DepthExceededStaxException();
+                    }
+                    stack.push(currentCount);
+                }
+                stack.push(0);
+            }
+
+        } else if (next == END_ELEMENT && props.getInnerElementCountThreshold() != -1) {
+            stack.pop();
+        }
+        return next;
+    }
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/DepthXMLStreamReader.java b/src/main/java/org/apache/xml/security/staxutils/DepthXMLStreamReader.java
new file mode 100644
index 0000000..3d7f14c
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/DepthXMLStreamReader.java
@@ -0,0 +1,266 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.xml.security.staxutils;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+public class DepthXMLStreamReader implements XMLStreamReader {
+
+    protected XMLStreamReader reader;
+    private int depth;
+
+    public DepthXMLStreamReader(XMLStreamReader r) {
+        this.reader = r;
+    }
+
+    public XMLStreamReader getReader() {
+        return this.reader;
+    }
+
+    public int getDepth() {
+        return depth;
+    }
+
+    public void close() throws XMLStreamException {
+        reader.close();
+    }
+
+    public int getAttributeCount() {
+        return reader.getAttributeCount();
+    }
+
+    public String getAttributeLocalName(int arg0) {
+        return reader.getAttributeLocalName(arg0);
+    }
+
+    public QName getAttributeName(int arg0) {
+        return reader.getAttributeName(arg0);
+    }
+
+    public String getAttributeNamespace(int arg0) {
+        return reader.getAttributeNamespace(arg0);
+    }
+
+    public String getAttributePrefix(int arg0) {
+        return reader.getAttributePrefix(arg0);
+    }
+
+    public String getAttributeType(int arg0) {
+        return reader.getAttributeType(arg0);
+    }
+
+    public String getAttributeValue(int arg0) {
+        return reader.getAttributeValue(arg0);
+    }
+
+    public String getAttributeValue(String namespace, String localName) {
+        return reader.getAttributeValue(namespace, localName);
+    }
+
+    public String getCharacterEncodingScheme() {
+        return reader.getCharacterEncodingScheme();
+    }
+
+    public String getElementText() throws XMLStreamException {
+        String ret = reader.getElementText();
+        //workaround bugs in some readers that aren't properly advancing to
+        //the END_ELEMENT (*cough*jettison*cough*)
+        while (reader.getEventType() != XMLStreamConstants.END_ELEMENT) {
+            reader.next();
+        }
+        depth--;
+        return ret;
+    }
+
+    public String getEncoding() {
+        return reader.getEncoding();
+    }
+
+    public int getEventType() {
+        return reader.getEventType();
+    }
+
+    public String getLocalName() {
+        return reader.getLocalName();
+    }
+
+    public Location getLocation() {
+        return reader.getLocation();
+    }
+
+    public QName getName() {
+        return reader.getName();
+    }
+
+    public NamespaceContext getNamespaceContext() {
+        return reader.getNamespaceContext();
+    }
+
+    public int getNamespaceCount() {
+        return reader.getNamespaceCount();
+    }
+
+    public String getNamespacePrefix(int arg0) {
+        return reader.getNamespacePrefix(arg0);
+    }
+
+    public String getNamespaceURI() {
+        return reader.getNamespaceURI();
+    }
+
+    public String getNamespaceURI(int arg0) {
+
+        return reader.getNamespaceURI(arg0);
+    }
+
+    public String getNamespaceURI(String arg0) {
+        return reader.getNamespaceURI(arg0);
+    }
+
+    public String getPIData() {
+        return reader.getPIData();
+    }
+
+    public String getPITarget() {
+        return reader.getPITarget();
+    }
+
+    public String getPrefix() {
+        return reader.getPrefix();
+    }
+
+    public Object getProperty(String arg0) throws IllegalArgumentException {
+
+        return reader.getProperty(arg0);
+    }
+
+    public String getText() {
+        return reader.getText();
+    }
+
+    public char[] getTextCharacters() {
+        return reader.getTextCharacters();
+    }
+
+    public int getTextCharacters(int arg0, char[] arg1, int arg2, int arg3) throws XMLStreamException {
+        return reader.getTextCharacters(arg0, arg1, arg2, arg3);
+    }
+
+    public int getTextLength() {
+        return reader.getTextLength();
+    }
+
+    public int getTextStart() {
+        return reader.getTextStart();
+    }
+
+    public String getVersion() {
+        return reader.getVersion();
+    }
+
+    public boolean hasName() {
+        return reader.hasName();
+    }
+
+    public boolean hasNext() throws XMLStreamException {
+        return reader.hasNext();
+    }
+
+    public boolean hasText() {
+        return reader.hasText();
+    }
+
+    public boolean isAttributeSpecified(int arg0) {
+        return reader.isAttributeSpecified(arg0);
+    }
+
+    public boolean isCharacters() {
+        return reader.isCharacters();
+    }
+
+    public boolean isEndElement() {
+        return reader.isEndElement();
+    }
+
+    public boolean isStandalone() {
+        return reader.isStandalone();
+    }
+
+    public boolean isStartElement() {
+        return reader.isStartElement();
+    }
+
+    public boolean isWhiteSpace() {
+        return reader.isWhiteSpace();
+    }
+
+    public int next() throws XMLStreamException {
+        int next = reader.next();
+
+        if (next == START_ELEMENT) {
+            depth++;
+        } else if (next == END_ELEMENT) {
+            depth--;
+        }
+
+        return next;
+    }
+
+    public int nextTag() throws XMLStreamException {
+        int eventType = next();
+        while (eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace()
+                || eventType == XMLStreamConstants.CDATA && isWhiteSpace()
+                // skip whitespace
+                || eventType == XMLStreamConstants.SPACE
+                || eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
+                || eventType == XMLStreamConstants.COMMENT) {
+            eventType = next();
+        }
+        if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT) {
+            throw new XMLStreamException("expected start or end tag", getLocation());
+        }
+        return eventType;
+    }
+
+    public void require(int arg0, String arg1, String arg2) throws XMLStreamException {
+        reader.require(arg0, arg1, arg2);
+    }
+
+    public boolean standaloneSet() {
+        return reader.standaloneSet();
+    }
+
+    public int hashCode() {
+        return reader.hashCode();
+    }
+
+    public boolean equals(Object arg0) {
+        return reader.equals(arg0);
+    }
+
+    public String toString() {
+        return reader.toString();
+    }
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/DocumentDepthProperties.java b/src/main/java/org/apache/xml/security/staxutils/DocumentDepthProperties.java
new file mode 100644
index 0000000..cdd9f4b
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/DocumentDepthProperties.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.staxutils;
+
+public class DocumentDepthProperties {
+
+    public static final String TOTAL_ELEMENT_COUNT = "depthTotalElementCountThreshold";
+    public static final String INNER_ELEMENT_COUNT = "depthInnerElementCountThreshold";
+    public static final String INNER_ELEMENT_LEVEL = "depthInnerElementLevelThreshold";
+
+    private int elementCountThreshold = -1;
+    private int innerElementLevelThreshold = -1;
+    private int innerElementCountThreshold = -1;
+    public DocumentDepthProperties() {
+
+    }
+    public DocumentDepthProperties(int elementCountThreshold,
+                                   int innerElementLevelThreshold,
+                                   int innerElementCountThreshold) {
+        this.elementCountThreshold = elementCountThreshold;
+        this.innerElementLevelThreshold = innerElementLevelThreshold;
+        this.innerElementCountThreshold = innerElementCountThreshold;
+    }
+
+    public boolean isEffective() {
+        return elementCountThreshold != -1 || innerElementLevelThreshold != -1
+            || innerElementCountThreshold != -1;
+    }
+
+    public void setElementCountThreshold(int elementCountThreshold) {
+        this.elementCountThreshold = elementCountThreshold;
+    }
+    public int getElementCountThreshold() {
+        return elementCountThreshold;
+    }
+    public void setInnerElementLevelThreshold(int innerElementLevelThreshold) {
+        this.innerElementLevelThreshold = innerElementLevelThreshold;
+    }
+    public int getInnerElementLevelThreshold() {
+        return innerElementLevelThreshold;
+    }
+    public void setInnerElementCountThreshold(int innerElementCountThreshold) {
+        this.innerElementCountThreshold = innerElementCountThreshold;
+    }
+    public int getInnerElementCountThreshold() {
+        return innerElementCountThreshold;
+    }
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/FastStack.java b/src/main/java/org/apache/xml/security/staxutils/FastStack.java
new file mode 100644
index 0000000..8a48a3d
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/FastStack.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.staxutils;
+
+import java.util.ArrayList;
+import java.util.EmptyStackException;
+
+public class FastStack<T> extends ArrayList<T> {
+    private static final long serialVersionUID = -6459503295618120689L;
+
+    public void push(T o) {
+        add(o);
+    }
+
+    public T pop() {
+        if (empty()) {
+            throw new EmptyStackException();
+        }
+
+        return remove(size() - 1);
+    }
+
+    public boolean empty() {
+        return size() == 0;
+    }
+
+    public T peek() {
+        if (empty()) {
+            throw new EmptyStackException();
+        }
+
+        return get(size() - 1);
+    }
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/StaxUtils.java b/src/main/java/org/apache/xml/security/staxutils/StaxUtils.java
new file mode 100644
index 0000000..756f6e9
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/StaxUtils.java
@@ -0,0 +1,592 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.xml.security.staxutils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.Stack;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLResolver;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.Source;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stax.StAXSource;
+import javax.xml.transform.stream.StreamSource;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.UserDataHandler;
+import org.xml.sax.InputSource;
+
+public final class StaxUtils {
+
+    private static final org.slf4j.Logger LOG =
+        org.slf4j.LoggerFactory.getLogger(StaxUtils.class);
+
+    private static final String XML_NS = "http://www.w3.org/2000/xmlns/";
+
+    private static final BlockingQueue<XMLInputFactory> DISALLOW_DOCTYPE_INPUT_FACTORY_POOL = new ArrayBlockingQueue<>(20);
+    private static final BlockingQueue<XMLInputFactory> ALLOW_DOCTYPE_INPUT_FACTORY_POOL = new ArrayBlockingQueue<>(20);
+
+    private StaxUtils() {
+    }
+
+    /**
+     * Return a cached, namespace-aware, factory.
+     */
+    private static XMLInputFactory getXMLInputFactory(boolean disAllowDocTypeDeclarations) {
+        XMLInputFactory f = disAllowDocTypeDeclarations
+            ? DISALLOW_DOCTYPE_INPUT_FACTORY_POOL.poll() : ALLOW_DOCTYPE_INPUT_FACTORY_POOL.poll();
+        if (f == null) {
+            f = createXMLInputFactory(disAllowDocTypeDeclarations);
+        }
+        return f;
+    }
+
+    private static void returnXMLInputFactory(XMLInputFactory factory, boolean disAllowDocTypeDeclarations) {
+        if (disAllowDocTypeDeclarations) {
+            DISALLOW_DOCTYPE_INPUT_FACTORY_POOL.offer(factory);
+        } else {
+            ALLOW_DOCTYPE_INPUT_FACTORY_POOL.offer(factory);
+        }
+    }
+
+    /**
+     * Return a new factory so that the caller can set sticky parameters.
+     * @param disAllowDocTypeDeclarations
+     * @throws XMLStreamException
+     */
+    private static XMLInputFactory createXMLInputFactory(boolean disAllowDocTypeDeclarations) {
+        XMLInputFactory factory = null;
+        try {
+            factory = XMLInputFactory.newInstance();
+        } catch (Throwable t) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("XMLInputFactory.newInstance() failed with: ", t);
+            }
+            throw new RuntimeException("Failed to create XMLInputFactory.");
+        }
+
+        setProperty(factory, XMLInputFactory.IS_NAMESPACE_AWARE, true);
+
+        if (disAllowDocTypeDeclarations) {
+            setProperty(factory, XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
+            setProperty(factory, XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, Boolean.FALSE);
+            setProperty(factory, XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
+            factory.setXMLResolver(new XMLResolver() {
+                public Object resolveEntity(String publicID, String systemID,
+                                            String baseURI, String namespace)
+                    throws XMLStreamException {
+                    throw new XMLStreamException("Reading external entities is disabled");
+                }
+            });
+        }
+
+        return factory;
+    }
+
+    private static boolean setProperty(XMLInputFactory f, String p, Object o) {
+        try {
+            f.setProperty(p,  o);
+            return true;
+        } catch (Throwable t) {
+            //ignore
+        }
+        return false;
+    }
+
+    public static Document read(Source s, boolean disAllowDocTypeDeclarations) throws XMLStreamException {
+        XMLStreamReader reader = createXMLStreamReader(s, disAllowDocTypeDeclarations);
+        try {
+            return read(reader);
+        } finally {
+            try {
+                reader.close();
+            } catch (Exception ex) {
+                //ignore
+            }
+        }
+    }
+    public static Document read(InputStream s, boolean disAllowDocTypeDeclarations) throws XMLStreamException {
+        XMLStreamReader reader = createXMLStreamReader(s, disAllowDocTypeDeclarations);
+        try {
+            return read(reader);
+        } finally {
+            try {
+                reader.close();
+            } catch (Exception ex) {
+                //ignore
+            }
+        }
+    }
+    public static Document read(Reader s, boolean disAllowDocTypeDeclarations) throws XMLStreamException {
+        XMLStreamReader reader = createXMLStreamReader(s, disAllowDocTypeDeclarations);
+        try {
+            return read(reader);
+        } finally {
+            try {
+                reader.close();
+            } catch (Exception ex) {
+                //ignore
+            }
+        }
+    }
+    public static Document read(File is, boolean disAllowDocTypeDeclarations) throws XMLStreamException, IOException {
+        try (InputStream fin = Files.newInputStream(is.toPath())) {
+            return read(fin, disAllowDocTypeDeclarations);
+        }
+    }
+    public static Document read(InputSource s, boolean disAllowDocTypeDeclarations) throws XMLStreamException {
+        XMLStreamReader reader = createXMLStreamReader(s, disAllowDocTypeDeclarations);
+        try {
+            return read(reader);
+        } finally {
+            try {
+                reader.close();
+            } catch (Exception ex) {
+                //ignore
+            }
+        }
+    }
+    public static Document read(XMLStreamReader reader) throws XMLStreamException {
+        return read(reader, false);
+    }
+    public static Document read(XMLStreamReader reader, boolean recordLoc) throws XMLStreamException {
+        Document doc = DOMUtils.newDocument(true);
+        if (reader.getLocation().getSystemId() != null) {
+            try {
+                doc.setDocumentURI(reader.getLocation().getSystemId());
+            } catch (Exception e) {
+                //ignore - probably not DOM level 3
+            }
+        }
+        readDocElements(doc, doc, reader, true, recordLoc);
+        return doc;
+    }
+
+    public static Document read(DocumentBuilder builder, XMLStreamReader reader, boolean repairing)
+        throws XMLStreamException {
+
+        Document doc = builder == null ? DOMUtils.newDocument(true) : builder.newDocument();
+        if (reader.getLocation().getSystemId() != null) {
+            try {
+                doc.setDocumentURI(reader.getLocation().getSystemId());
+            } catch (Exception e) {
+                //ignore - probably not DOM level 3
+            }
+        }
+        readDocElements(doc, reader, repairing);
+        return doc;
+    }
+
+    /**
+     * @param parent
+     */
+    private static Document getDocument(Node parent) {
+        return parent instanceof Document ? (Document)parent : parent.getOwnerDocument();
+    }
+
+    private static boolean isDeclared(Element e, String namespaceURI, String prefix) {
+        while (e != null) {
+            Attr att;
+            if (prefix != null && prefix.length() > 0) {
+                att = e.getAttributeNodeNS(XML_NS, prefix);
+            } else {
+                att = e.getAttributeNode("xmlns");
+            }
+
+            if (att != null && att.getNodeValue().equals(namespaceURI)) {
+                return true;
+            }
+
+            if (e.getParentNode() instanceof Element) {
+                e = (Element)e.getParentNode();
+            } else if (isEmpty(prefix) && isEmpty(namespaceURI)) {
+                //A document that probably doesn't have any namespace qualifies elements
+                return true;
+            } else {
+                e = null;
+            }
+        }
+        return false;
+    }
+
+    public static void readDocElements(Node parent, XMLStreamReader reader, boolean repairing)
+        throws XMLStreamException {
+        Document doc = getDocument(parent);
+        readDocElements(doc, parent, reader, repairing, false);
+    }
+
+    public static void readDocElements(Node parent, XMLStreamReader reader, boolean repairing,
+                                       boolean isThreshold)
+        throws XMLStreamException {
+        Document doc = getDocument(parent);
+        readDocElements(doc, parent, reader, repairing, false, isThreshold);
+    }
+
+    /**
+     * @param parent
+     * @param reader
+     * @throws XMLStreamException
+     */
+    public static void readDocElements(Document doc, Node parent,
+                                       XMLStreamReader reader, boolean repairing, boolean recordLoc)
+        throws XMLStreamException {
+        readDocElements(doc, parent, reader, repairing, recordLoc, false);
+    }
+
+    /**
+     * @param parent
+     * @param reader
+     * @throws XMLStreamException
+     */
+    public static void readDocElements(Document doc, Node parent,
+                                       XMLStreamReader reader, boolean repairing, boolean recordLoc,
+                                       boolean isThreshold)
+        throws XMLStreamException {
+        Stack<Node> stack = new Stack<Node>();
+        int event = reader.getEventType();
+        while (reader.hasNext()) {
+            switch (event) {
+            case XMLStreamConstants.START_ELEMENT: {
+                Element e;
+                if (!isEmpty(reader.getPrefix())) {
+                    e = doc.createElementNS(reader.getNamespaceURI(),
+                                            reader.getPrefix() + ":" + reader.getLocalName());
+                } else {
+                    e = doc.createElementNS(reader.getNamespaceURI(), reader.getLocalName());
+                }
+                e = (Element)parent.appendChild(e);
+                recordLoc = addLocation(doc, e, reader, recordLoc);
+
+                for (int ns = 0; ns < reader.getNamespaceCount(); ns++) {
+                    String uri = reader.getNamespaceURI(ns);
+                    String prefix = reader.getNamespacePrefix(ns);
+
+                    declare(e, uri, prefix);
+                }
+
+                for (int att = 0; att < reader.getAttributeCount(); att++) {
+                    String name = reader.getAttributeLocalName(att);
+                    String prefix = reader.getAttributePrefix(att);
+                    if (prefix != null && prefix.length() > 0) {
+                        name = prefix + ":" + name;
+                    }
+
+                    Attr attr = doc.createAttributeNS(reader.getAttributeNamespace(att), name);
+                    attr.setValue(reader.getAttributeValue(att));
+                    e.setAttributeNode(attr);
+                }
+
+                if (repairing && !isDeclared(e, reader.getNamespaceURI(), reader.getPrefix())) {
+                    declare(e, reader.getNamespaceURI(), reader.getPrefix());
+                }
+                stack.push(parent);
+                parent = e;
+                break;
+            }
+            case XMLStreamConstants.END_ELEMENT:
+                if (stack.isEmpty()) {
+                    return;
+                }
+                parent = stack.pop();
+                //if (parent instanceof Document || parent instanceof DocumentFragment) {
+                //    return;
+                //}
+                break;
+            case XMLStreamConstants.NAMESPACE:
+                break;
+            case XMLStreamConstants.ATTRIBUTE:
+                break;
+            case XMLStreamConstants.CHARACTERS:
+                if (parent != null) {
+                    recordLoc = addLocation(doc,
+                                            parent.appendChild(doc.createTextNode(reader.getText())),
+                                            reader, recordLoc);
+                }
+                break;
+            case XMLStreamConstants.COMMENT:
+                if (parent != null) {
+                    parent.appendChild(doc.createComment(reader.getText()));
+                }
+                break;
+            case XMLStreamConstants.CDATA:
+                recordLoc = addLocation(doc,
+                                        parent.appendChild(doc.createCDATASection(reader.getText())),
+                                        reader, recordLoc);
+                break;
+            case XMLStreamConstants.PROCESSING_INSTRUCTION:
+                parent.appendChild(doc.createProcessingInstruction(reader.getPITarget(), reader.getPIData()));
+                break;
+            case XMLStreamConstants.ENTITY_REFERENCE:
+                parent.appendChild(doc.createProcessingInstruction(reader.getPITarget(), reader.getPIData()));
+                break;
+            default:
+                break;
+            }
+
+            if (reader.hasNext()) {
+                event = reader.next();
+            }
+        }
+    }
+
+    private static boolean addLocation(Document doc, Node node,
+                                       Location loc,
+                                       boolean recordLoc) {
+        if (recordLoc && loc != null && (loc.getColumnNumber() != 0 || loc.getLineNumber() != 0)) {
+            try {
+                final int charOffset = loc.getCharacterOffset();
+                final int colNum = loc.getColumnNumber();
+                final int linNum = loc.getLineNumber();
+                final String pubId = loc.getPublicId() == null ? doc.getDocumentURI() : loc.getPublicId();
+                final String sysId = loc.getSystemId() == null ? doc.getDocumentURI() : loc.getSystemId();
+                Location loc2 = new Location() {
+                    public int getCharacterOffset() {
+                        return charOffset;
+                    }
+                    public int getColumnNumber() {
+                        return colNum;
+                    }
+                    public int getLineNumber() {
+                        return linNum;
+                    }
+                    public String getPublicId() {
+                        return pubId;
+                    }
+                    public String getSystemId() {
+                        return sysId;
+                    }
+                };
+                node.setUserData("location", loc2, LocationUserDataHandler.INSTANCE);
+            } catch (Throwable ex) {
+                //possibly not DOM level 3, won't be able to record this then
+                return false;
+            }
+        }
+        return recordLoc;
+    }
+
+    private static boolean addLocation(Document doc, Node node,
+                                    XMLStreamReader reader,
+                                    boolean recordLoc) {
+        return addLocation(doc, node, reader.getLocation(), recordLoc);
+    }
+
+    private static class LocationUserDataHandler implements UserDataHandler {
+        public static final LocationUserDataHandler INSTANCE = new LocationUserDataHandler();
+
+        public void handle(short operation, String key, Object data, Node src, Node dst) {
+            if (operation == NODE_CLONED) {
+                dst.setUserData(key, data, this);
+            }
+        }
+    }
+
+    private static void declare(Element node, String uri, String prefix) {
+        String qualname;
+        if (prefix != null && prefix.length() > 0) {
+            qualname = "xmlns:" + prefix;
+        } else {
+            qualname = "xmlns";
+        }
+        Attr attr = node.getOwnerDocument().createAttributeNS(XML_NS, qualname);
+        attr.setValue(uri);
+        node.setAttributeNodeNS(attr);
+    }
+
+    public static XMLStreamReader createXMLStreamReader(InputSource src, boolean disAllowDocTypeDeclarations) {
+        String sysId = src.getSystemId() == null ? null : src.getSystemId();
+        String pubId = src.getPublicId() == null ? null : src.getPublicId();
+        if (src.getByteStream() != null) {
+            if (src.getEncoding() == null) {
+                StreamSource ss = new StreamSource(src.getByteStream(), sysId);
+                ss.setPublicId(pubId);
+                return createXMLStreamReader(ss, disAllowDocTypeDeclarations);
+            }
+            return createXMLStreamReader(src.getByteStream(), src.getEncoding(), disAllowDocTypeDeclarations);
+        } else if (src.getCharacterStream() != null) {
+            StreamSource ss = new StreamSource(src.getCharacterStream(), sysId);
+            ss.setPublicId(pubId);
+            return createXMLStreamReader(ss, disAllowDocTypeDeclarations);
+        } else {
+            try {
+                URL url = new URL(sysId);
+                StreamSource ss = new StreamSource(url.openStream(), sysId);
+                ss.setPublicId(pubId);
+                return createXMLStreamReader(ss, disAllowDocTypeDeclarations);
+            } catch (Exception ex) {
+                //ignore - not a valid URL
+            }
+        }
+        throw new IllegalArgumentException("InputSource must have a ByteStream or CharacterStream");
+    }
+    /**
+     * @param in
+     * @param encoding
+     */
+    public static XMLStreamReader createXMLStreamReader(InputStream in, String encoding, boolean disAllowDocTypeDeclarations) {
+        if (encoding == null) {
+            encoding = StandardCharsets.UTF_8.name();
+        }
+
+        XMLInputFactory factory = getXMLInputFactory(disAllowDocTypeDeclarations);
+        try {
+            return factory.createXMLStreamReader(in, encoding);
+        } catch (XMLStreamException e) {
+            throw new RuntimeException("Couldn't parse stream.", e);
+        } finally {
+            returnXMLInputFactory(factory, disAllowDocTypeDeclarations);
+        }
+    }
+
+    /**
+     * @param in
+     */
+    public static XMLStreamReader createXMLStreamReader(InputStream in, boolean disAllowDocTypeDeclarations) {
+        XMLInputFactory factory = getXMLInputFactory(disAllowDocTypeDeclarations);
+        try {
+            return factory.createXMLStreamReader(in);
+        } catch (XMLStreamException e) {
+            throw new RuntimeException("Couldn't parse stream.", e);
+        } finally {
+            returnXMLInputFactory(factory, disAllowDocTypeDeclarations);
+        }
+    }
+    public static XMLStreamReader createXMLStreamReader(String systemId, InputStream in, boolean disAllowDocTypeDeclarations) {
+        XMLInputFactory factory = getXMLInputFactory(disAllowDocTypeDeclarations);
+        try {
+            return factory.createXMLStreamReader(systemId, in);
+        } catch (XMLStreamException e) {
+            throw new RuntimeException("Couldn't parse stream.", e);
+        } finally {
+            returnXMLInputFactory(factory, disAllowDocTypeDeclarations);
+        }
+    }
+
+    public static XMLStreamReader createXMLStreamReader(Element el) {
+        return new W3CDOMStreamReader(el);
+    }
+    public static XMLStreamReader createXMLStreamReader(Document doc) {
+        return new W3CDOMStreamReader(doc.getDocumentElement());
+    }
+    public static XMLStreamReader createXMLStreamReader(Element el, String sysId) {
+        return new W3CDOMStreamReader(el, sysId);
+    }
+    public static XMLStreamReader createXMLStreamReader(Document doc, String sysId) {
+        return new W3CDOMStreamReader(doc.getDocumentElement(), sysId);
+    }
+
+    public static XMLStreamReader createXMLStreamReader(Source source, boolean disAllowDocTypeDeclarations) {
+        try {
+            if (source instanceof DOMSource) {
+                DOMSource ds = (DOMSource)source;
+                Node nd = ds.getNode();
+                Element el = null;
+                if (nd instanceof Document) {
+                    el = ((Document)nd).getDocumentElement();
+                } else if (nd instanceof Element) {
+                    el = (Element)nd;
+                }
+
+                if (null != el) {
+                    return new W3CDOMStreamReader(el, source.getSystemId());
+                }
+            } else if (source instanceof StAXSource) {
+                return ((StAXSource)source).getXMLStreamReader();
+            } else if (source instanceof SAXSource) {
+                SAXSource ss = (SAXSource)source;
+                if (ss.getXMLReader() == null) {
+                    return createXMLStreamReader(((SAXSource)source).getInputSource(), disAllowDocTypeDeclarations);
+                }
+            }
+
+            XMLInputFactory factory = getXMLInputFactory(disAllowDocTypeDeclarations);
+            try {
+                XMLStreamReader reader = null;
+
+                try {
+                    reader = factory.createXMLStreamReader(source);
+                } catch (UnsupportedOperationException e) {
+                    //ignore
+                }
+                if (reader == null && source instanceof StreamSource) {
+                    //createXMLStreamReader from Source is optional, we'll try and map it
+                    StreamSource ss = (StreamSource)source;
+                    if (ss.getInputStream() != null) {
+                        reader = factory.createXMLStreamReader(ss.getSystemId(),
+                                                               ss.getInputStream());
+                    } else {
+                        reader = factory.createXMLStreamReader(ss.getSystemId(),
+                                                               ss.getReader());
+                    }
+                }
+                return reader;
+            } finally {
+                returnXMLInputFactory(factory, disAllowDocTypeDeclarations);
+            }
+        } catch (XMLStreamException e) {
+            throw new RuntimeException("Couldn't parse stream.", e);
+        }
+    }
+
+    /**
+     * @param reader
+     */
+    public static XMLStreamReader createXMLStreamReader(Reader reader, boolean disAllowDocTypeDeclarations) {
+        XMLInputFactory factory = getXMLInputFactory(disAllowDocTypeDeclarations);
+        try {
+            return factory.createXMLStreamReader(reader);
+        } catch (XMLStreamException e) {
+            throw new RuntimeException("Couldn't parse stream.", e);
+        } finally {
+            returnXMLInputFactory(factory, disAllowDocTypeDeclarations);
+        }
+    }
+
+    private static boolean isEmpty(String str) {
+        if (str != null) {
+            int len = str.length();
+            for (int x = 0; x < len; ++x) {
+                if (str.charAt(x) > ' ') {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/SystemPropertyAction.java b/src/main/java/org/apache/xml/security/staxutils/SystemPropertyAction.java
new file mode 100644
index 0000000..5757e60
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/SystemPropertyAction.java
@@ -0,0 +1,97 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.xml.security.staxutils;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ *
+ */
+public final class SystemPropertyAction implements PrivilegedAction<String> {
+    private static final org.slf4j.Logger LOG =
+        org.slf4j.LoggerFactory.getLogger(SystemPropertyAction.class);
+    private final String property;
+    private final String def;
+    private SystemPropertyAction(String name) {
+        property = name;
+        def = null;
+    }
+    private SystemPropertyAction(String name, String d) {
+        property = name;
+        def = d;
+    }
+
+    /* (non-Javadoc)
+     * @see java.security.PrivilegedAction#run()
+     */
+    public String run() {
+        if (def != null) {
+            return System.getProperty(property, def);
+        }
+        return System.getProperty(property);
+    }
+
+    public static String getProperty(String name) {
+        return AccessController.doPrivileged(new SystemPropertyAction(name));
+    }
+
+    public static String getProperty(String name, String def) {
+        try {
+            return AccessController.doPrivileged(new SystemPropertyAction(name, def));
+        } catch (SecurityException ex) {
+            LOG.debug("SecurityException raised getting property " + name, ex);
+            return def;
+        }
+    }
+
+    /**
+     * Get the system property via the AccessController, but if a SecurityException is
+     * raised, just return null;
+     * @param name
+     */
+    public static String getPropertyOrNull(String name) {
+        try {
+            return AccessController.doPrivileged(new SystemPropertyAction(name));
+        } catch (SecurityException ex) {
+            LOG.debug("SecurityException raised getting property " + name, ex);
+            return null;
+        }
+    }
+
+    /**
+     * Get the integer system property via the AccessController, but if a SecurityException is
+     * raised, just return the default;
+     * @param name - system property name
+     * @param def - the default value if the system property does not exist or cannot be acquired
+     */
+    public static int getInteger(String name, int def) {
+        try {
+            return AccessController.doPrivileged(new PrivilegedAction<Integer>() {
+                @Override
+                public Integer run() {
+                    return Integer.getInteger(name, def);
+                } });
+        } catch (SecurityException ex) {
+            LOG.debug("SecurityException raised getting property " + name, ex);
+            return def;
+        }
+    }
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/W3CDOMStreamReader.java b/src/main/java/org/apache/xml/security/staxutils/W3CDOMStreamReader.java
new file mode 100644
index 0000000..9596d74
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/W3CDOMStreamReader.java
@@ -0,0 +1,419 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.staxutils;
+
+import java.util.ArrayList;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamException;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+import org.w3c.dom.TypeInfo;
+
+public class W3CDOMStreamReader extends AbstractDOMStreamReader<Node, Node> {
+    private Node content;
+
+    private Document document;
+
+    private W3CNamespaceContext context;
+
+    private String sysId;
+
+    /**
+     * @param element
+     */
+    public W3CDOMStreamReader(Element element) {
+        super(new ElementFrame<Node, Node>(element, null));
+        content = element;
+        newFrame(getCurrentFrame());
+
+        this.document = element.getOwnerDocument();
+    }
+    public W3CDOMStreamReader(Element element, String systemId) {
+        this(element);
+        sysId = systemId;
+    }
+    public W3CDOMStreamReader(Document doc) {
+        super(new ElementFrame<Node, Node>(doc, false) {
+            public boolean isDocument() {
+                return true;
+            }
+        });
+        this.document = doc;
+    }
+    public W3CDOMStreamReader(DocumentFragment docfrag) {
+        super(new ElementFrame<Node, Node>(docfrag, true) {
+            public boolean isDocumentFragment() {
+                return true;
+            }
+        });
+        this.document = docfrag.getOwnerDocument();
+    }
+
+    /**
+     * Get the document associated with this stream.
+     */
+    public Document getDocument() {
+        return document;
+    }
+    public String getSystemId() {
+        try {
+            return sysId == null ? document.getDocumentURI() : sysId;
+        } catch (Throwable ex) {
+            //ignore, probably not DOM level 3
+        }
+        return sysId;
+    }
+    /**
+     * Find name spaces declaration in atrributes and move them to separate
+     * collection.
+     */
+    @Override
+    protected final void newFrame(ElementFrame<Node, Node> frame) {
+        Node element = getCurrentNode();
+        frame.uris = new ArrayList<>();
+        frame.prefixes = new ArrayList<>();
+        frame.attributes = new ArrayList<>();
+
+        if (context == null) {
+            context = new W3CNamespaceContext();
+        }
+        if (element instanceof Element) {
+            context.setElement((Element)element);
+        }
+
+        NamedNodeMap nodes = element.getAttributes();
+
+        String ePrefix = element.getPrefix();
+        if (ePrefix == null) {
+            ePrefix = "";
+        }
+
+        if (nodes != null) {
+            for (int i = 0; i < nodes.getLength(); i++) {
+                Node node = nodes.item(i);
+                String prefix = node.getPrefix();
+                String localName = node.getLocalName();
+                String value = node.getNodeValue();
+                String name = node.getNodeName();
+
+                if (prefix == null) {
+                    prefix = "";
+                }
+
+                if (name != null && "xmlns".equals(name)) {
+                    frame.uris.add(value);
+                    frame.prefixes.add("");
+                } else if (prefix.length() > 0 && "xmlns".equals(prefix)) {
+                    frame.uris.add(value);
+                    frame.prefixes.add(localName);
+                } else if (name.startsWith("xmlns:")) {
+                    prefix = name.substring(6);
+                    frame.uris.add(value);
+                    frame.prefixes.add(prefix);
+                } else {
+                    frame.attributes.add(node);
+                }
+            }
+        }
+    }
+
+    public final Node getCurrentNode() {
+        return getCurrentFrame().element;
+    }
+    public final Element getCurrentElement() {
+        return (Element)getCurrentFrame().element;
+    }
+
+    @Override
+    protected ElementFrame<Node, Node> getChildFrame() {
+        return new ElementFrame<Node, Node>(getCurrentFrame().currentChild,
+                                getCurrentFrame());
+    }
+
+    @Override
+    protected boolean hasMoreChildren() {
+        if (getCurrentFrame().currentChild == null) {
+            return getCurrentNode().getFirstChild() != null;
+        }
+        return getCurrentFrame().currentChild.getNextSibling() != null;
+    }
+
+    @Override
+    protected int nextChild() {
+        ElementFrame<Node, Node> frame = getCurrentFrame();
+        if (frame.currentChild == null) {
+            content = getCurrentNode().getFirstChild();
+        } else {
+            content = frame.currentChild.getNextSibling();
+        }
+
+        frame.currentChild = content;
+        switch (content.getNodeType()) {
+        case Node.ELEMENT_NODE:
+            return START_ELEMENT;
+        case Node.TEXT_NODE:
+            return CHARACTERS;
+        case Node.COMMENT_NODE:
+            return COMMENT;
+        case Node.CDATA_SECTION_NODE:
+            return CDATA;
+        case Node.ENTITY_REFERENCE_NODE:
+            return ENTITY_REFERENCE;
+        case Node.PROCESSING_INSTRUCTION_NODE:
+            return PROCESSING_INSTRUCTION;
+        default:
+            throw new IllegalStateException("Found type: " + content.getClass().getName());
+        }
+    }
+
+    @Override
+    public String getElementText() throws XMLStreamException {
+        String result = DOMUtils.getRawContent(content);
+
+        ElementFrame<Node, Node> frame = getCurrentFrame();
+        frame.ended = true;
+        currentEvent = END_ELEMENT;
+        endElement();
+
+        // we should not return null according to the StAx API javadoc
+        return result != null ? result : "";
+    }
+
+    @Override
+    public String getNamespaceURI(String prefix) {
+        ElementFrame<Node, Node> frame = getCurrentFrame();
+
+        while (null != frame) {
+            int index = frame.prefixes.indexOf(prefix);
+            if (index != -1) {
+                return frame.uris.get(index);
+            }
+
+            if (frame.parent == null && frame.getElement() instanceof Element) {
+                return ((Element)frame.getElement()).lookupNamespaceURI(prefix);
+            }
+            frame = frame.parent;
+        }
+
+        return null;
+    }
+
+    public String getAttributeValue(String ns, String local) {
+        Attr at;
+        if (ns == null || ns.equals("")) {
+            at = getCurrentElement().getAttributeNode(local);
+        } else {
+            at = getCurrentElement().getAttributeNodeNS(ns, local);
+        }
+
+        if (at == null) {
+            return null;
+        }
+        return at.getNodeValue();
+    }
+
+    public int getAttributeCount() {
+        return getCurrentFrame().attributes.size();
+    }
+
+    Attr getAttribute(int i) {
+        return (Attr)getCurrentFrame().attributes.get(i);
+    }
+
+    private String getLocalName(Attr attr) {
+
+        String name = attr.getLocalName();
+        if (name == null) {
+            name = attr.getNodeName();
+        }
+        return name;
+    }
+
+    public QName getAttributeName(int i) {
+        Attr at = getAttribute(i);
+
+        String prefix = at.getPrefix();
+        String ln = getLocalName(at);
+        // at.getNodeName();
+        String ns = at.getNamespaceURI();
+
+        if (prefix == null) {
+            return new QName(ns, ln);
+        }
+        return new QName(ns, ln, prefix);
+    }
+
+    public String getAttributeNamespace(int i) {
+        return getAttribute(i).getNamespaceURI();
+    }
+
+    public String getAttributeLocalName(int i) {
+        Attr attr = getAttribute(i);
+        return getLocalName(attr);
+    }
+
+    public String getAttributePrefix(int i) {
+        return getAttribute(i).getPrefix();
+    }
+
+    public String getAttributeType(int i) {
+        Attr attr = getAttribute(i);
+        if (attr.isId()) {
+            return "ID";
+        }
+        TypeInfo schemaType = null;
+        try {
+            schemaType = attr.getSchemaTypeInfo();
+        } catch (Throwable t) {
+            //DOM level 2?
+            schemaType = null;
+        }
+        return (schemaType == null) ? "CDATA"
+            : schemaType.getTypeName() == null ? "CDATA" : schemaType.getTypeName();
+    }
+
+
+    public String getAttributeValue(int i) {
+        return getAttribute(i).getValue();
+    }
+
+    public boolean isAttributeSpecified(int i) {
+        return getAttribute(i).getValue() != null;
+    }
+
+    public int getNamespaceCount() {
+        return getCurrentFrame().prefixes.size();
+    }
+
+    public String getNamespacePrefix(int i) {
+        return getCurrentFrame().prefixes.get(i);
+    }
+
+    public String getNamespaceURI(int i) {
+        return getCurrentFrame().uris.get(i);
+    }
+
+    public NamespaceContext getNamespaceContext() {
+        return context;
+    }
+
+    public String getText() {
+        if (content instanceof Text) {
+            return ((Text)content).getData();
+        } else if (content instanceof Comment) {
+            return ((Comment)content).getData();
+        }
+        return DOMUtils.getRawContent(getCurrentNode());
+    }
+
+    public char[] getTextCharacters() {
+        return getText().toCharArray();
+    }
+
+    public int getTextStart() {
+        return 0;
+    }
+
+    public int getTextLength() {
+        return getText().length();
+    }
+
+    public String getEncoding() {
+        return null;
+    }
+
+    public QName getName() {
+        Node el = getCurrentNode();
+
+        String prefix = getPrefix();
+        String ln = getLocalName();
+
+        return new QName(el.getNamespaceURI(), ln, prefix);
+    }
+
+    public String getLocalName() {
+        String ln = getCurrentNode().getLocalName();
+        if (ln == null) {
+            ln = getCurrentNode().getNodeName();
+            if (ln.indexOf(":") != -1) {
+                ln = ln.substring(ln.indexOf(":") + 1);
+            }
+        }
+        return ln;
+    }
+
+    public String getNamespaceURI() {
+        String ln = getCurrentNode().getLocalName();
+        if (ln == null) {
+            ln = getCurrentNode().getNodeName();
+            if (ln.indexOf(":") == -1) {
+                ln = getNamespaceURI("");
+            } else {
+                ln = getNamespaceURI(ln.substring(0, ln.indexOf(":")));
+            }
+            return ln;
+        }
+        return getCurrentNode().getNamespaceURI();
+    }
+
+    public String getPrefix() {
+        String prefix = getCurrentNode().getPrefix();
+        if (prefix == null) {
+            String nodeName = getCurrentNode().getNodeName();
+            if (nodeName.indexOf(":") != -1) {
+                prefix = nodeName.substring(0, nodeName.indexOf(":"));
+            }  else {
+                prefix = "";
+            }
+        }
+        return prefix;
+    }
+
+    public String getPITarget() {
+        return ((ProcessingInstruction)content).getTarget();
+    }
+
+    public String getPIData() {
+        return ((ProcessingInstruction)content).getData();
+    }
+    public Location getLocation() {
+        try {
+            Object o = getCurrentNode().getUserData("location");
+            if (o instanceof Location) {
+                return (Location)o;
+            }
+        } catch (Throwable ex) {
+            //ignore, probably not DOM level 3
+        }
+        return super.getLocation();
+    }
+
+
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/W3CNamespaceContext.java b/src/main/java/org/apache/xml/security/staxutils/W3CNamespaceContext.java
new file mode 100644
index 0000000..647e6dc
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/W3CNamespaceContext.java
@@ -0,0 +1,141 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.xml.security.staxutils;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.namespace.NamespaceContext;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+public class W3CNamespaceContext implements NamespaceContext {
+    private Element currentNode;
+    private NamespaceContext outNamespaceContext;
+
+    public W3CNamespaceContext() {
+    }
+    public W3CNamespaceContext(Element el) {
+        currentNode = el;
+    }
+
+    public void setOutNamespaceContext(NamespaceContext context) {
+        outNamespaceContext = context;
+    }
+
+    public String getNamespaceURI(String prefix) {
+        String name = prefix;
+        if (name.length() == 0) {
+            name = "xmlns";
+        } else {
+            name = "xmlns:" + prefix;
+        }
+
+        return getNamespaceURI(currentNode, name);
+    }
+
+    private String getNamespaceURI(Element e, String name) {
+        if (e == null) {
+            return null;
+        }
+        // check the outside namespace URI
+        if (outNamespaceContext != null) {
+            String result = outNamespaceContext.getNamespaceURI(name);
+            if (result != null) {
+                return result;
+            }
+        }
+
+        Attr attr = e.getAttributeNode(name);
+        if (attr == null) {
+            Node n = e.getParentNode();
+            if (n instanceof Element && n != e) {
+                return getNamespaceURI((Element)n, name);
+            }
+        } else {
+            return attr.getValue();
+        }
+
+        return null;
+    }
+
+    public String getPrefix(String uri) {
+        return getPrefix(currentNode, uri);
+    }
+
+    private String getPrefix(Element e, String uri) {
+        if (e == null) {
+            return null;
+        }
+        // check the outside namespace URI
+        if (outNamespaceContext != null) {
+            String result = outNamespaceContext.getPrefix(uri);
+            if (result != null) {
+                return result;
+            }
+        }
+
+        NamedNodeMap attributes = e.getAttributes();
+        if (attributes != null) {
+            for (int i = 0; i < attributes.getLength(); i++) {
+                Attr a = (Attr)attributes.item(i);
+
+                String val = a.getValue();
+                if (val != null && val.equals(uri)) {
+                    String name = a.getLocalName();
+                    if ("xmlns".equals(name)) {
+                        return "";
+                    }
+                    return name;
+                }
+            }
+        }
+
+        Node n = e.getParentNode();
+        if (n instanceof Element && n != e) {
+            return getPrefix((Element)n, uri);
+        }
+
+        return null;
+    }
+
+    public Iterator<String> getPrefixes(String uri) {
+        List<String> prefixes = new ArrayList<>();
+
+        String prefix = getPrefix(uri);
+        if (prefix != null) {
+            prefixes.add(prefix);
+        }
+
+        return prefixes.iterator();
+    }
+
+    public Element getElement() {
+        return currentNode;
+    }
+
+    public void setElement(Element node) {
+        this.currentNode = node;
+    }
+}
diff --git a/src/main/java/org/apache/xml/security/transforms/implementations/TransformBase64Decode.java b/src/main/java/org/apache/xml/security/transforms/implementations/TransformBase64Decode.java
index 0c1b3c6..e94e115 100644
--- a/src/main/java/org/apache/xml/security/transforms/implementations/TransformBase64Decode.java
+++ b/src/main/java/org/apache/xml/security/transforms/implementations/TransformBase64Decode.java
@@ -22,6 +22,7 @@
 import java.io.OutputStream;
 
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
 
 import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.signature.XMLSignatureInput;
@@ -156,6 +157,8 @@
             throw new TransformationException(e, "c14n.Canonicalizer.Exception");
         } catch (SAXException e) {
             throw new TransformationException(e, "SAX exception");
+        } catch (XMLStreamException e) {
+            throw new TransformationException(e, "SAX exception");
         }
     }
 
diff --git a/src/main/java/org/apache/xml/security/transforms/implementations/TransformXPath2Filter.java b/src/main/java/org/apache/xml/security/transforms/implementations/TransformXPath2Filter.java
index 9844670..3726a8f 100644
--- a/src/main/java/org/apache/xml/security/transforms/implementations/TransformXPath2Filter.java
+++ b/src/main/java/org/apache/xml/security/transforms/implementations/TransformXPath2Filter.java
@@ -26,6 +26,7 @@
 import java.util.Set;
 
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
 import javax.xml.transform.TransformerException;
 
 import org.apache.xml.security.c14n.CanonicalizationException;
@@ -144,11 +145,7 @@
             throw new TransformationException(ex);
         } catch (XMLSecurityException ex) {
             throw new TransformationException(ex);
-        } catch (SAXException ex) {
-            throw new TransformationException(ex);
-        } catch (IOException ex) {
-            throw new TransformationException(ex);
-        } catch (ParserConfigurationException ex) {
+        } catch (ParserConfigurationException | IOException | SAXException | XMLStreamException ex) {
             throw new TransformationException(ex);
         }
     }
diff --git a/src/main/java/org/apache/xml/security/utils/XMLUtils.java b/src/main/java/org/apache/xml/security/utils/XMLUtils.java
index 2cc91f4..5f964a1 100644
--- a/src/main/java/org/apache/xml/security/utils/XMLUtils.java
+++ b/src/main/java/org/apache/xml/security/utils/XMLUtils.java
@@ -31,14 +31,15 @@
 import java.util.List;
 import java.util.Set;
 
-import javax.xml.XMLConstants;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
 
 import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.c14n.Canonicalizer;
 import org.apache.xml.security.c14n.InvalidCanonicalizerException;
+import org.apache.xml.security.staxutils.DOMUtils;
+import org.apache.xml.security.staxutils.StaxUtils;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -59,13 +60,6 @@
         AccessController.doPrivileged(
             (PrivilegedAction<Boolean>) () -> Boolean.getBoolean("org.apache.xml.security.ignoreLineBreaks"));
 
-    @SuppressWarnings("unchecked")
-    private static final WeakObjectPool<DocumentBuilder, ParserConfigurationException> pools[] = new WeakObjectPool[2];
-    static {
-        pools[0] = new DocumentBuilderPool(false);
-        pools[1] = new DocumentBuilderPool(true);
-    }
-
     private static volatile String dsPrefix = "ds";
     private static volatile String ds11Prefix = "dsig11";
     private static volatile String xencPrefix = "xenc";
@@ -1004,55 +998,61 @@
     }
 
     public static Document newDocument() throws ParserConfigurationException {
-        DocumentBuilder documentBuilder = createDocumentBuilder(true);
-        Document doc = documentBuilder.newDocument();
-        repoolDocumentBuilder(documentBuilder, true);
-        return doc;
+        return DOMUtils.newDocument(true);
     }
 
-    public static Document read(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException {
+    public static Document read(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
         return read(inputStream, true);
     }
 
-    public static Document read(InputStream inputStream, boolean disAllowDocTypeDeclarations) throws ParserConfigurationException, SAXException, IOException {
-        DocumentBuilder documentBuilder = createDocumentBuilder(disAllowDocTypeDeclarations);
-        Document doc = documentBuilder.parse(inputStream);
-        repoolDocumentBuilder(documentBuilder, disAllowDocTypeDeclarations);
-        return doc;
+    public static Document read(InputStream inputStream, boolean disAllowDocTypeDeclarations)
+        throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
+        XMLStreamReader reader = StaxUtils.createXMLStreamReader(inputStream, disAllowDocTypeDeclarations);
+        try {
+            Document doc = DOMUtils.newDocument(disAllowDocTypeDeclarations);
+            if (reader.getLocation().getSystemId() != null) {
+                try {
+                    doc.setDocumentURI(reader.getLocation().getSystemId());
+                } catch (Exception e) {
+                    //ignore - probably not DOM level 3
+                }
+            }
+            StaxUtils.readDocElements(doc, doc, reader, true, false);
+            return doc;
+        } finally {
+            try {
+                reader.close();
+            } catch (Exception ex) {
+                //ignore
+            }
+        }
     }
 
-    public static Document read(String uri, boolean disAllowDocTypeDeclarations)
-        throws ParserConfigurationException, SAXException, IOException {
-        DocumentBuilder documentBuilder = createDocumentBuilder(disAllowDocTypeDeclarations);
-        Document doc = documentBuilder.parse(uri);
-        repoolDocumentBuilder(documentBuilder, disAllowDocTypeDeclarations);
-        return doc;
-    }
-
-    public static Document read(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException {
+    public static Document read(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
         return read(inputSource, true);
     }
 
     public static Document read(InputSource inputSource, boolean disAllowDocTypeDeclarations)
-        throws ParserConfigurationException, SAXException, IOException {
-        DocumentBuilder documentBuilder = createDocumentBuilder(disAllowDocTypeDeclarations);
-        Document doc = documentBuilder.parse(inputSource);
-        repoolDocumentBuilder(documentBuilder, disAllowDocTypeDeclarations);
-        return doc;
-    }
-
-    private static DocumentBuilder createDocumentBuilder(
-        boolean disAllowDocTypeDeclarations
-    ) throws ParserConfigurationException {
-        int idx = getPoolsIndex(disAllowDocTypeDeclarations);
-        return pools[idx].getObject();
-    }
-
-
-    private static boolean repoolDocumentBuilder(DocumentBuilder db, boolean disAllowDocTypeDeclarations) {
-        db.reset();
-        int idx = getPoolsIndex(disAllowDocTypeDeclarations);
-        return pools[idx].repool(db);
+        throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
+        XMLStreamReader reader = StaxUtils.createXMLStreamReader(inputSource, disAllowDocTypeDeclarations);
+        try {
+            Document doc = DOMUtils.newDocument(disAllowDocTypeDeclarations);
+            if (reader.getLocation().getSystemId() != null) {
+                try {
+                    doc.setDocumentURI(reader.getLocation().getSystemId());
+                } catch (Exception e) {
+                    //ignore - probably not DOM level 3
+                }
+            }
+            StaxUtils.readDocElements(doc, doc, reader, true, false);
+            return doc;
+        } finally {
+            try {
+                reader.close();
+            } catch (Exception ex) {
+                //ignore
+            }
+        }
     }
 
     /**
@@ -1100,34 +1100,4 @@
         return resizedBytes;
     }
 
-    private static final class DocumentBuilderPool
-        extends WeakObjectPool<DocumentBuilder, ParserConfigurationException> {
-
-        private final boolean disAllowDocTypeDeclarations;
-
-        public DocumentBuilderPool(boolean disAllowDocTypeDeclarations) {
-            this.disAllowDocTypeDeclarations = disAllowDocTypeDeclarations;
-        }
-
-        @Override
-        protected DocumentBuilder createObject() throws ParserConfigurationException {
-            DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
-            dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
-            if (disAllowDocTypeDeclarations) {
-                dfactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
-            }
-            dfactory.setNamespaceAware(true);
-            return dfactory.newDocumentBuilder();
-        }
-    }
-
-    /**
-     * Maps the boolean configuration options for the factories to the array index for the WeakObjectPool
-     * @param disAllowDocTypeDeclarations
-     * @return the index to the {@link #pools}
-     */
-    private static int getPoolsIndex(boolean disAllowDocTypeDeclarations) {
-        return (disAllowDocTypeDeclarations ? 1 : 0);
-    }
-
 }
diff --git a/src/test/java/org/apache/xml/security/test/dom/TestUtils.java b/src/test/java/org/apache/xml/security/test/dom/TestUtils.java
index 8bdacc2..53f9484 100644
--- a/src/test/java/org/apache/xml/security/test/dom/TestUtils.java
+++ b/src/test/java/org/apache/xml/security/test/dom/TestUtils.java
@@ -18,9 +18,19 @@
  */
 package org.apache.xml.security.test.dom;
 
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.xml.security.staxutils.DOMUtils;
+import org.apache.xml.security.staxutils.StaxUtils;
 import org.apache.xml.security.utils.Constants;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
 
 public class TestUtils {
 
@@ -42,4 +52,27 @@
         return ctx;
     }
 
+    public static Document read(String uri, String systemId, boolean disAllowDocTypeDeclarations)
+        throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
+        XMLStreamReader reader = StaxUtils.createXMLStreamReader(systemId, new FileInputStream(uri), disAllowDocTypeDeclarations);
+        try {
+            Document doc = DOMUtils.newDocument(disAllowDocTypeDeclarations);
+            if (reader.getLocation().getSystemId() != null) {
+                try {
+                    doc.setDocumentURI(reader.getLocation().getSystemId());
+                } catch (Exception e) {
+                    //ignore - probably not DOM level 3
+                }
+            }
+            StaxUtils.readDocElements(doc, doc, reader, true, false);
+            return doc;
+        } finally {
+            try {
+                reader.close();
+            } catch (Exception ex) {
+                //ignore
+            }
+        }
+    }
+
 }
diff --git a/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer11Test.java b/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer11Test.java
index 3522a8b..3a75bab 100644
--- a/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer11Test.java
+++ b/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer11Test.java
@@ -32,8 +32,8 @@
 
 import org.apache.xml.security.c14n.Canonicalizer;
 import org.apache.xml.security.test.dom.DSNamespaceContext;
+import org.apache.xml.security.test.dom.TestUtils;
 import org.apache.xml.security.utils.JavaUtils;
-import org.apache.xml.security.utils.XMLUtils;
 import org.w3c.dom.Document;
 import org.w3c.dom.NodeList;
 
@@ -244,7 +244,8 @@
         Map<String, String> namespaces
     ) throws Exception {
 
-        Document doc = XMLUtils.read(fileIn, false);
+        String systemId = "target/test-classes/org/apache/xml/security/c14n/in/xyz";
+        Document doc = TestUtils.read(fileIn, systemId, false);
 
         Canonicalizer c14n = Canonicalizer.getInstance(c14nURI);
         byte[] c14nBytes = null;
diff --git a/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer20010315Test.java b/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer20010315Test.java
index 3116d51..f2d810e 100644
--- a/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer20010315Test.java
+++ b/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer20010315Test.java
@@ -42,6 +42,7 @@
 import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.c14n.Canonicalizer;
 import org.apache.xml.security.test.dom.DSNamespaceContext;
+import org.apache.xml.security.test.dom.TestUtils;
 import org.apache.xml.security.utils.JavaUtils;
 import org.apache.xml.security.utils.XMLUtils;
 import org.w3c.dom.Document;
@@ -710,7 +711,8 @@
         Map<String, String> namespaces
     ) throws Exception {
 
-        Document doc = XMLUtils.read(fileIn, false);
+        String systemId = "target/test-classes/org/apache/xml/security/c14n/in/xyz";
+        Document doc = TestUtils.read(fileIn, systemId, false);
 
 
         Canonicalizer c14n = Canonicalizer.getInstance(c14nURI);
diff --git a/src/test/java/org/apache/xml/security/test/dom/interop/InteropTestBase.java b/src/test/java/org/apache/xml/security/test/dom/interop/InteropTestBase.java
index 7eaf26b..8dabaec 100644
--- a/src/test/java/org/apache/xml/security/test/dom/interop/InteropTestBase.java
+++ b/src/test/java/org/apache/xml/security/test/dom/interop/InteropTestBase.java
@@ -36,6 +36,7 @@
 import org.apache.xml.security.signature.reference.ReferenceNodeSetData;
 import org.apache.xml.security.signature.reference.ReferenceOctetStreamData;
 import org.apache.xml.security.test.dom.DSNamespaceContext;
+import org.apache.xml.security.test.dom.TestUtils;
 import org.apache.xml.security.utils.XMLUtils;
 import org.apache.xml.security.utils.resolver.ResourceResolverSpi;
 import org.w3c.dom.Element;
@@ -91,8 +92,13 @@
     public boolean verify(String filename, ResourceResolverSpi resolver,
                           boolean followManifests, boolean secureValidation)
         throws Exception {
-        File f = new File(filename);
-        org.w3c.dom.Document doc = XMLUtils.read(new FileInputStream(f), false);
+        return verify(filename, resolver, null, followManifests, secureValidation);
+    }
+
+    public boolean verify(String filename, ResourceResolverSpi resolver, String systemId,
+                          boolean followManifests, boolean secureValidation)
+        throws Exception {
+        org.w3c.dom.Document doc = TestUtils.read(filename, systemId, false);
 
         XPathFactory xpf = XPathFactory.newInstance();
         XPath xpath = xpf.newXPath();
@@ -101,6 +107,7 @@
         String expression = "//ds:Signature[1]";
         Element sigElement =
             (Element) xpath.evaluate(expression, doc, XPathConstants.NODE);
+        File f = new File(filename);
         XMLSignature signature = new XMLSignature(sigElement, f.toURI().toURL().toString(), secureValidation);
 
         if (resolver != null) {