From a232c2954a9451aed25c0bdcf7c7a5b93878e913 Mon Sep 17 00:00:00 2001 From: "Yuan.Wang" <1536296691@qq.com> Date: Fri, 9 Jun 2023 14:01:48 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-95578=20dom4j=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dom4j/dtd/Decl.java | 7 + .../java/org/dom4j/io/DOMDocumentResult.java | 102 ++++ .../org/dom4j/io/DOMSAXContentHandler.java | 548 ++++++++++++++++++ .../main/java/org/dom4j/util/StringUtils.java | 44 ++ 4 files changed, 701 insertions(+) create mode 100644 fine-org-dom4j/src/main/java/org/dom4j/dtd/Decl.java create mode 100644 fine-org-dom4j/src/main/java/org/dom4j/io/DOMDocumentResult.java create mode 100644 fine-org-dom4j/src/main/java/org/dom4j/io/DOMSAXContentHandler.java create mode 100644 fine-org-dom4j/src/main/java/org/dom4j/util/StringUtils.java diff --git a/fine-org-dom4j/src/main/java/org/dom4j/dtd/Decl.java b/fine-org-dom4j/src/main/java/org/dom4j/dtd/Decl.java new file mode 100644 index 000000000..f05d32df5 --- /dev/null +++ b/fine-org-dom4j/src/main/java/org/dom4j/dtd/Decl.java @@ -0,0 +1,7 @@ +package org.dom4j.dtd; + +/** + * Created by filip on 5.7.15. + */ +public interface Decl { +} diff --git a/fine-org-dom4j/src/main/java/org/dom4j/io/DOMDocumentResult.java b/fine-org-dom4j/src/main/java/org/dom4j/io/DOMDocumentResult.java new file mode 100644 index 000000000..5f579bbe3 --- /dev/null +++ b/fine-org-dom4j/src/main/java/org/dom4j/io/DOMDocumentResult.java @@ -0,0 +1,102 @@ +/* + * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved. + * + * This software is open source. + * See the bottom of this file for the licence. + */ + +package org.dom4j.io; + +import javax.xml.transform.sax.SAXResult; + +import org.w3c.dom.Document; + +import org.xml.sax.ContentHandler; +import org.xml.sax.ext.LexicalHandler; + +/** + *
+ * DOMDocumentResult
implements a JAXP {@link SAXResult} for a
+ * {@link org.w3c.dom.Document}.
+ *
+ * SAXContentHandler
builds W3C DOM object via SAX events.
+ *
+ * @author James Strachan
+ * @author Todd Wolff
+ *
+ *
Document
instances */
+ private DOMDocumentFactory documentFactory;
+
+ /** The document that is being built */
+ private Document document;
+
+ /** stack of Element
objects */
+ private ElementStack elementStack;
+
+ /** stack of Namespace
and QName
objects */
+ private NamespaceStack namespaceStack;
+
+ /** the Locator */
+ private Locator locator;
+
+ /** Flag used to indicate that we are inside a CDATA section */
+ private boolean insideCDATASection;
+
+ /**
+ * buffer to hold contents of cdata section across multiple characters
+ * events
+ */
+ private StringBuffer cdataText;
+
+ /** The number of namespaces that are declared in the current scope */
+ private int declaredNamespaceIndex;
+
+ private InputSource inputSource;
+
+ /** The current element we are on */
+ private Element currentElement;
+
+ /** The entity resolver */
+ private EntityResolver entityResolver;
+
+ /** Whether adjacent text nodes should be merged */
+ private boolean mergeAdjacentText = false;
+
+ /** Have we added text to the buffer */
+ private boolean textInTextBuffer = false;
+
+ /** Should we ignore comments */
+ private boolean ignoreComments = false;
+
+ /** Buffer used to concatenate text together */
+ private StringBuffer textBuffer;
+
+ /** Holds value of property stripWhitespaceText. */
+ private boolean stripWhitespaceText = false;
+
+ public DOMSAXContentHandler() {
+ this((DOMDocumentFactory)DOMDocumentFactory.getInstance());
+ }
+
+ public DOMSAXContentHandler(DOMDocumentFactory documentFactory) {
+ this.documentFactory = documentFactory;
+ this.elementStack = createElementStack();
+ this.namespaceStack = new NamespaceStack(documentFactory);
+ }
+
+ /**
+ * Retrieves w3c document object built via generated sax events.
+ *
+ * @return the document that has been or is being built
+ */
+ public org.w3c.dom.Document getDocument() {
+ if (document == null) {
+ document = createDocument();
+ }
+
+ return (org.w3c.dom.Document)document;
+ }
+
+ // ContentHandler interface
+ // -------------------------------------------------------------------------
+ public void setDocumentLocator(Locator documentLocator) {
+ this.locator = documentLocator;
+ }
+
+ public void processingInstruction(String target, String data)
+ throws SAXException {
+ if (mergeAdjacentText && textInTextBuffer) {
+ completeCurrentTextNode();
+ }
+ ProcessingInstruction pi = (ProcessingInstruction)documentFactory.createProcessingInstruction(target, data);
+ if (currentElement != null) {
+ ((org.w3c.dom.Element)currentElement).appendChild(pi);
+ } else {
+ getDocument().appendChild(pi);
+ }
+ }
+
+ public void startPrefixMapping(String prefix, String uri)
+ throws SAXException {
+ namespaceStack.push(prefix, uri);
+ }
+
+ public void endPrefixMapping(String prefix) throws SAXException {
+ namespaceStack.pop(prefix);
+ declaredNamespaceIndex = namespaceStack.size();
+ }
+
+ public void startDocument() throws SAXException {
+ document = null;
+ currentElement = null;
+
+ elementStack.clear();
+
+ namespaceStack.clear();
+ declaredNamespaceIndex = 0;
+
+ if (mergeAdjacentText && (textBuffer == null)) {
+ textBuffer = new StringBuffer();
+ }
+
+ textInTextBuffer = false;
+ }
+
+ public void endDocument() throws SAXException {
+ namespaceStack.clear();
+ elementStack.clear();
+ currentElement = null;
+ textBuffer = null;
+ }
+
+ public void startElement(String namespaceURI, String localName,
+ String qualifiedName, Attributes attributes) throws SAXException {
+ if (mergeAdjacentText && textInTextBuffer) {
+ completeCurrentTextNode();
+ }
+
+ QName qName = namespaceStack.getQName(namespaceURI, localName,
+ qualifiedName);
+
+ Branch branch = currentElement;
+
+ if (branch == null) {
+ branch = (org.dom4j.Document)getDocument();
+ }
+
+ Element element = new DOMElement(qName);
+ branch.add(element);
+
+ // add all declared namespaces
+ addDeclaredNamespaces(element);
+
+ // now lets add all attribute values
+ addAttributes(element, attributes);
+
+ elementStack.pushElement(element);
+ currentElement = element;
+
+ }
+
+ public void endElement(String namespaceURI, String localName, String qName)
+ throws SAXException {
+ if (mergeAdjacentText && textInTextBuffer) {
+ completeCurrentTextNode();
+ }
+
+ elementStack.popElement();
+ currentElement = elementStack.peekElement();
+ }
+
+ public void characters(char[] ch, int start, int end) throws SAXException {
+ if (end == 0) {
+ return;
+ }
+
+ if (currentElement != null) {
+ if (insideCDATASection) {
+ if (mergeAdjacentText && textInTextBuffer) {
+ completeCurrentTextNode();
+ }
+ cdataText.append(new String(ch, start, end));
+ } else {
+ if (mergeAdjacentText) {
+ textBuffer.append(ch, start, end);
+ textInTextBuffer = true;
+ } else {
+ DOMText text = new DOMText(new String(ch, start, end));
+ ((DOMElement)currentElement).add(text);
+ }
+ }
+ }
+ }
+
+ // ErrorHandler interface
+ // -------------------------------------------------------------------------
+
+ /**
+ * This method is called when a warning occurs during the parsing of the
+ * document. This method does nothing.
+ *
+ * @param exception
+ * DOCUMENT ME!
+ *
+ * @throws SAXException
+ * DOCUMENT ME!
+ */
+ public void warning(SAXParseException exception) throws SAXException {
+ // ignore warnings by default
+ }
+
+ /**
+ * This method is called when an error is detected during parsing such as a
+ * validation error. This method rethrows the exception
+ *
+ * @param exception
+ * DOCUMENT ME!
+ *
+ * @throws SAXException
+ * DOCUMENT ME!
+ */
+ public void error(SAXParseException exception) throws SAXException {
+ throw exception;
+ }
+
+ /**
+ * This method is called when a fatal error occurs during parsing. This
+ * method rethrows the exception
+ *
+ * @param exception
+ * DOCUMENT ME!
+ *
+ * @throws SAXException
+ * DOCUMENT ME!
+ */
+ public void fatalError(SAXParseException exception) throws SAXException {
+ throw exception;
+ }
+
+ // LexicalHandler interface
+ // -------------------------------------------------------------------------
+ public void startDTD(String name, String publicId, String systemId)
+ throws SAXException {
+ // not supported
+ }
+
+ public void endDTD() throws SAXException {
+ // not supported
+ }
+
+ public void startEntity(String name) throws SAXException {
+ // not supported
+ }
+
+ public void endEntity(String name) throws SAXException {
+ // not supported
+ }
+
+ public void startCDATA() throws SAXException {
+ insideCDATASection = true;
+ cdataText = new StringBuffer();
+ }
+
+ public void endCDATA() throws SAXException {
+ insideCDATASection = false;
+ DOMCDATA cdata = new DOMCDATA(cdataText.toString());
+ ((DOMElement)currentElement).add(cdata);
+ }
+
+ public void comment(char[] ch, int start, int end) throws SAXException {
+ if (!ignoreComments) {
+ if (mergeAdjacentText && textInTextBuffer) {
+ completeCurrentTextNode();
+ }
+
+ String text = new String(ch, start, end);
+
+ if (text.length() > 0) {
+ DOMComment domComment = new DOMComment(text);
+ if (currentElement != null) {
+ ((DOMElement)currentElement).add(domComment);
+ } else {
+ getDocument().appendChild(domComment);
+ }
+ }
+ }
+ }
+
+ // Properties
+ // -------------------------------------------------------------------------
+ public ElementStack getElementStack() {
+ return elementStack;
+ }
+
+ public void setElementStack(ElementStack elementStack) {
+ this.elementStack = elementStack;
+ }
+
+ public EntityResolver getEntityResolver() {
+ return entityResolver;
+ }
+
+ public void setEntityResolver(EntityResolver entityResolver) {
+ this.entityResolver = entityResolver;
+ }
+
+ public InputSource getInputSource() {
+ return inputSource;
+ }
+
+ public void setInputSource(InputSource inputSource) {
+ this.inputSource = inputSource;
+ }
+
+ /**
+ * Returns whether adjacent text nodes should be merged together.
+ *
+ * @return Value of property mergeAdjacentText.
+ */
+ public boolean isMergeAdjacentText() {
+ return mergeAdjacentText;
+ }
+
+ /**
+ * Sets whether or not adjacent text nodes should be merged together when
+ * parsing.
+ *
+ * @param mergeAdjacentText
+ * New value of property mergeAdjacentText.
+ */
+ public void setMergeAdjacentText(boolean mergeAdjacentText) {
+ this.mergeAdjacentText = mergeAdjacentText;
+ }
+
+ /**
+ * Sets whether whitespace between element start and end tags should be
+ * ignored
+ *
+ * @return Value of property stripWhitespaceText.
+ */
+ public boolean isStripWhitespaceText() {
+ return stripWhitespaceText;
+ }
+
+ /**
+ * Sets whether whitespace between element start and end tags should be
+ * ignored.
+ *
+ * @param stripWhitespaceText
+ * New value of property stripWhitespaceText.
+ */
+ public void setStripWhitespaceText(boolean stripWhitespaceText) {
+ this.stripWhitespaceText = stripWhitespaceText;
+ }
+
+ /**
+ * Returns whether we should ignore comments or not.
+ *
+ * @return boolean
+ */
+ public boolean isIgnoreComments() {
+ return ignoreComments;
+ }
+
+ /**
+ * Sets whether we should ignore comments or not.
+ *
+ * @param ignoreComments
+ * whether we should ignore comments or not.
+ */
+ public void setIgnoreComments(boolean ignoreComments) {
+ this.ignoreComments = ignoreComments;
+ }
+
+ // Implementation methods
+ // -------------------------------------------------------------------------
+
+ protected void completeCurrentTextNode() {
+ if (stripWhitespaceText) {
+ boolean whitespace = true;
+ for (int i = 0, size = textBuffer.length(); i < size; i++) {
+ if (!Character.isWhitespace(textBuffer.charAt(i))) {
+ whitespace = false;
+
+ break;
+ }
+ }
+ if (!whitespace) {
+ DOMText domText = new DOMText(textBuffer.toString());
+ ((DOMElement)currentElement).add(domText);
+ }
+ } else {
+ DOMText domText = new DOMText(textBuffer.toString());
+ ((DOMElement)currentElement).add(domText);
+ }
+
+ textBuffer.setLength(0);
+ textInTextBuffer = false;
+ }
+
+ protected Document createDocument() {
+ String encoding = getEncoding();
+ Document doc = documentFactory.createDocument(encoding);
+
+ // set the EntityResolver
+ doc.setEntityResolver(entityResolver);
+
+ if (inputSource != null) {
+ doc.setName(inputSource.getSystemId());
+ }
+
+ return doc;
+ }
+
+ private String getEncoding() {
+ if (locator == null) {
+ return null;
+ }
+
+ if (locator instanceof Locator2) {
+ return ((Locator2) locator).getEncoding();
+ }
+
+ // couldn't determine encoding, returning null...
+ return null;
+ }
+
+ protected void addDeclaredNamespaces(Element element) {
+ for (int size = namespaceStack.size(); declaredNamespaceIndex < size;
+ declaredNamespaceIndex++) {
+ Namespace namespace = namespaceStack
+ .getNamespace(declaredNamespaceIndex);
+ String attributeName = attributeNameForNamespace(namespace);
+ ((DOMElement)element).setAttribute(attributeName, namespace.getURI());
+ }
+ }
+
+ protected void addAttributes(Element element, Attributes attributes) {
+ int size = attributes.getLength();
+ for (int i = 0; i < size; i++) {
+ String attributeQName = attributes.getQName(i);
+ if (!attributeQName.startsWith("xmlns")) {
+ String attributeURI = attributes.getURI(i);
+ String attributeLocalName = attributes.getLocalName(i);
+ String attributeValue = attributes.getValue(i);
+ QName qName = namespaceStack.getAttributeQName(
+ attributeURI, attributeLocalName, attributeQName);
+ DOMAttribute domAttribute = new DOMAttribute(qName, attributeValue);
+ ((DOMElement)element).setAttributeNode(domAttribute);
+ }
+ }
+ }
+
+ protected ElementStack createElementStack() {
+ return new ElementStack();
+ }
+
+ protected String attributeNameForNamespace(Namespace namespace) {
+ String xmlns = "xmlns";
+ String prefix = namespace.getPrefix();
+
+ if (prefix.length() > 0) {
+ return xmlns + ":" + prefix;
+ }
+
+ return xmlns;
+ }
+
+}
+
+/*
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * 1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name "DOM4J" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of MetaStuff, Ltd. For
+ * written permission, please contact dom4j-info@metastuff.com.
+ *
+ * 4. Products derived from this Software may not be called "DOM4J" nor may
+ * "DOM4J" appear in their names without prior written permission of MetaStuff,
+ * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
+ *
+ * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
+ *
+ * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
+ */
diff --git a/fine-org-dom4j/src/main/java/org/dom4j/util/StringUtils.java b/fine-org-dom4j/src/main/java/org/dom4j/util/StringUtils.java
new file mode 100644
index 000000000..694e3b99e
--- /dev/null
+++ b/fine-org-dom4j/src/main/java/org/dom4j/util/StringUtils.java
@@ -0,0 +1,44 @@
+package org.dom4j.util;
+
+/**
+ * Contains utilities related to strings.
+ *
+ * @author Marián Petráš
+ */
+public final class StringUtils {
+
+ private StringUtils() {}
+
+ /**
+ * Finds out if the given character sequence starts with a whitespace
+ * character.
+ *
+ * @return {@code true} if the given character sequence is not empty
+ * and starts with a whitespace character; {@code false} otherwise
+ * @exception NullPointerException if the given character sequence is
+ * {@code null}
+ */
+ public static boolean startsWithWhitespace(final CharSequence charSeq) {
+ if (charSeq.length() == 0) {
+ return false;
+ }
+ return Character.isWhitespace(charSeq.charAt(0));
+ }
+
+ /**
+ * Finds out if the given character sequence ends with a whitespace
+ * character.
+ *
+ * @return {@code true} if the given character sequence is not empty
+ * and ends with a whitespace character; {@code false} otherwise
+ * @exception NullPointerException if the given character sequence is
+ * {@code null}
+ */
+ public static boolean endsWithWhitespace(final CharSequence charSeq) {
+ if (charSeq.length() == 0) {
+ return false;
+ }
+ return Character.isWhitespace(charSeq.charAt(charSeq.length() - 1));
+ }
+
+}