Moved Spring-WS to separate dir.
This commit is contained in:
80
xml/src/main/java/org/springframework/xml/JaxpVersion.java
Normal file
80
xml/src/main/java/org/springframework/xml/JaxpVersion.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml;
|
||||
|
||||
/**
|
||||
* Helper class used to find the current version of JAXP. We cannot depend on the Java version, since JAXP can be
|
||||
* upgraded idenpendantly of the Java version.
|
||||
* <p/>
|
||||
* Only distinguishes between JAXP 1.0, 1.1, 1.3, and 1.4, since JAXP 1.2 was a maintenance release with no new
|
||||
* classes.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public abstract class JaxpVersion {
|
||||
|
||||
public static final int JAXP_10 = 0;
|
||||
|
||||
public static final int JAXP_11 = 1;
|
||||
|
||||
public static final int JAXP_13 = 3;
|
||||
|
||||
public static final int JAXP_14 = 4;
|
||||
|
||||
private static final String JAXP_11_CLASS_NAME = "javax.xml.transform.Transformer";
|
||||
|
||||
private static final String JAXP_13_CLASS_NAME = "javax.xml.xpath.XPath";
|
||||
|
||||
private static final String JAXP_14_CLASS_NAME = "javax.xml.transform.stax.StAXSource";
|
||||
|
||||
private static int jaxpVersion = JAXP_10;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class.forName(JAXP_14_CLASS_NAME);
|
||||
jaxpVersion = JAXP_14;
|
||||
}
|
||||
catch (ClassNotFoundException ex1) {
|
||||
try {
|
||||
Class.forName(JAXP_13_CLASS_NAME);
|
||||
jaxpVersion = JAXP_13;
|
||||
}
|
||||
catch (ClassNotFoundException ex2) {
|
||||
try {
|
||||
Class.forName(JAXP_11_CLASS_NAME);
|
||||
jaxpVersion = JAXP_11;
|
||||
}
|
||||
catch (ClassNotFoundException ex3) {
|
||||
// default to JAXP 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the major JAXP version. This means we can do things like if <code>(getJaxpVersion() < JAXP_13)</code>.
|
||||
*
|
||||
* @return a code comparable to the JAXP_XX codes in this class
|
||||
* @see #JAXP_10
|
||||
* @see #JAXP_11
|
||||
* @see #JAXP_13
|
||||
* @see #JAXP_14
|
||||
*/
|
||||
public static int getJaxpVersion() {
|
||||
return jaxpVersion;
|
||||
}
|
||||
}
|
||||
46
xml/src/main/java/org/springframework/xml/XmlException.java
Normal file
46
xml/src/main/java/org/springframework/xml/XmlException.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Root of the hierarchy of XML exception.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public abstract class XmlException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>XmlException</code> with the specific detail message.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
protected XmlException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>XmlException</code> with the specific detail message and exception.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param throwable the wrapped exception
|
||||
*/
|
||||
protected XmlException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2005 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.namespace;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* PropertyEditor for <code>javax.xml.namespace.QName</code>, to populate a property of type QName from a String value.
|
||||
* <p/>
|
||||
* Expects the syntax
|
||||
* <pre>
|
||||
* localPart
|
||||
* </pre>
|
||||
* or
|
||||
* <pre>
|
||||
* {namespace}localPart
|
||||
* </pre>
|
||||
* or
|
||||
* <pre>
|
||||
* {namespace}prefix:localPart
|
||||
* </pre>
|
||||
* This resembles the <code>toString()</code> representation of <code>QName</code> itself, but allows for prefixes to be
|
||||
* specified as well.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see javax.xml.namespace.QName
|
||||
* @see javax.xml.namespace.QName#toString()
|
||||
* @see javax.xml.namespace.QName#valueOf(String)
|
||||
*/
|
||||
public class QNameEditor extends PropertyEditorSupport {
|
||||
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
setValue(QNameUtils.parseQNameString(text));
|
||||
}
|
||||
|
||||
public String getAsText() {
|
||||
Object value = getValue();
|
||||
if (value == null || !(value instanceof QName)) {
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
QName qName = (QName) value;
|
||||
String prefix = QNameUtils.getPrefix(qName);
|
||||
if (StringUtils.hasLength(qName.getNamespaceURI()) && StringUtils.hasLength(prefix)) {
|
||||
return "{" + qName.getNamespaceURI() + "}" + prefix + ":" + qName.getLocalPart();
|
||||
}
|
||||
else if (StringUtils.hasLength(qName.getNamespaceURI())) {
|
||||
return "{" + qName.getNamespaceURI() + "}" + qName.getLocalPart();
|
||||
}
|
||||
else {
|
||||
return qName.getLocalPart();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2005 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.namespace;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Helper class for using <code>javax.xml.namespace.QName</code>.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see javax.xml.namespace.QName
|
||||
*/
|
||||
public abstract class QNameUtils {
|
||||
|
||||
private static boolean qNameHasPrefix;
|
||||
|
||||
static {
|
||||
try {
|
||||
QName.class.getDeclaredConstructor(new Class[]{String.class, String.class, String.class});
|
||||
qNameHasPrefix = true;
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
qNameHasPrefix = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>QName</code> with the given parameters. Sets the prefix if possible, i.e. if the
|
||||
* <code>QName(String, String, String)</code> constructor can be found. If this constructor is not available (as is
|
||||
* the case on older implementations of JAX-RPC), the prefix is ignored.
|
||||
*
|
||||
* @param namespaceUri namespace URI of the <code>QName</code>
|
||||
* @param localPart local part of the <code>QName</code>
|
||||
* @param prefix prefix of the <code>QName</code>. May be ignored.
|
||||
* @return the created <code>QName</code>
|
||||
* @see QName#QName(String, String, String)
|
||||
*/
|
||||
public static QName createQName(String namespaceUri, String localPart, String prefix) {
|
||||
if (qNameHasPrefix) {
|
||||
return new QName(namespaceUri, localPart, prefix);
|
||||
}
|
||||
else {
|
||||
return new QName(namespaceUri, localPart);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prefix of the given <code>QName</code>. Returns the prefix if available, i.e. if the
|
||||
* <code>QName.getPrefix()</code> method can be found. If this method is not available (as is the case on older
|
||||
* implementations of JAX-RPC), an empty string is returned.
|
||||
*
|
||||
* @param qName the <code>QName</code> to return the prefix from
|
||||
* @return the prefix, if available, or an empty string
|
||||
* @see javax.xml.namespace.QName#getPrefix()
|
||||
*/
|
||||
public static String getPrefix(QName qName) {
|
||||
return qNameHasPrefix ? qName.getPrefix() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the given String as a QName
|
||||
*
|
||||
* @param text the qualified name
|
||||
* @return <code>true</code> if valid, <code>false</code> otherwise
|
||||
*/
|
||||
public static boolean validateQName(String text) {
|
||||
if (!StringUtils.hasLength(text)) {
|
||||
return false;
|
||||
}
|
||||
if (text.charAt(0) == '{') {
|
||||
int i = text.indexOf('}');
|
||||
|
||||
if (i == -1 || i == text.length() - 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the qualified name of the given DOM Node.
|
||||
*
|
||||
* @param node the node
|
||||
* @return the qualified name of the node
|
||||
*/
|
||||
public static QName getQNameForNode(Node node) {
|
||||
if (node.getNamespaceURI() != null && node.getPrefix() != null && node.getLocalName() != null) {
|
||||
return createQName(node.getNamespaceURI(), node.getLocalName(), node.getPrefix());
|
||||
}
|
||||
else if (node.getNamespaceURI() != null && node.getLocalName() != null) {
|
||||
return new QName(node.getNamespaceURI(), node.getLocalName());
|
||||
}
|
||||
else if (node.getLocalName() != null) {
|
||||
return new QName(node.getLocalName());
|
||||
}
|
||||
else {
|
||||
// as a last resort, use the node name
|
||||
return new QName(node.getNodeName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a <code>QName</code> to a qualified name, as used by DOM and SAX. The returned string has a format of
|
||||
* <code>prefix:localName</code> if the prefix is set, or just <code>localName</code> if not.
|
||||
*
|
||||
* @param qName the <code>QName</code>
|
||||
* @return the qualified name
|
||||
*/
|
||||
public static String toQualifiedName(QName qName) {
|
||||
String prefix = getPrefix(qName);
|
||||
if (!StringUtils.hasLength(prefix)) {
|
||||
return qName.getLocalPart();
|
||||
}
|
||||
else {
|
||||
return prefix + ":" + qName.getLocalPart();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a namespace URI and DOM or SAX qualified name to a <code>QName</code>. The qualified name can have the
|
||||
* form <code>prefix:localname</code> or <code>localName</code>.
|
||||
*
|
||||
* @param namespaceUri the namespace URI
|
||||
* @param qualifiedName the qualified name
|
||||
* @return a QName
|
||||
*/
|
||||
public static QName toQName(String namespaceUri, String qualifiedName) {
|
||||
int idx = qualifiedName.indexOf(':');
|
||||
if (idx == -1) {
|
||||
return new QName(namespaceUri, qualifiedName);
|
||||
}
|
||||
else {
|
||||
return createQName(namespaceUri, qualifiedName.substring(idx + 1), qualifiedName.substring(0, idx));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given qualified name string into a <code>QName</code>. Expects the syntax <code>localPart</code>,
|
||||
* <code>{namespace}localPart</code>, or <code>{namespace}prefix:localPart</code>. This format resembles the
|
||||
* <code>toString()</code> representation of <code>QName</code> itself, but allows for prefixes to be specified as
|
||||
* well.
|
||||
*
|
||||
* @return a corresponding QName instance
|
||||
* @throws IllegalArgumentException when the given string is <code>null</code> or empty.
|
||||
*/
|
||||
public static QName parseQNameString(String qNameString) {
|
||||
Assert.hasLength(qNameString, "QName text may not be null or empty");
|
||||
if (qNameString.charAt(0) != '{') {
|
||||
return new QName(qNameString);
|
||||
}
|
||||
else {
|
||||
int endOfNamespaceURI = qNameString.indexOf('}');
|
||||
if (endOfNamespaceURI == -1) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot create QName from \"" + qNameString + "\", missing closing \"}\"");
|
||||
}
|
||||
int prefixSeperator = qNameString.indexOf(':', endOfNamespaceURI + 1);
|
||||
String namespaceURI = qNameString.substring(1, endOfNamespaceURI);
|
||||
if (prefixSeperator == -1) {
|
||||
return new QName(namespaceURI, qNameString.substring(endOfNamespaceURI + 1));
|
||||
}
|
||||
else {
|
||||
return createQName(namespaceURI, qNameString.substring(prefixSeperator + 1),
|
||||
qNameString.substring(endOfNamespaceURI + 1, prefixSeperator));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.namespace;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple <code>javax.xml.namespace.NamespaceContext</code> implementation. Follows the standard
|
||||
* <code>NamespaceContext</code> contract, and is loadable via a <code>java.util.Map</code> or
|
||||
* <code>java.util.Properties</code> object
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class SimpleNamespaceContext implements NamespaceContext {
|
||||
|
||||
private Map prefixToNamespaceUri = new HashMap();
|
||||
|
||||
/**
|
||||
* Maps a <code>String</code> namespaceUri to a <code>List</code> of prefixes
|
||||
*/
|
||||
private Map namespaceUriToPrefixes = new HashMap();
|
||||
|
||||
private String defaultNamespaceUri = "";
|
||||
|
||||
public String getNamespaceURI(String prefix) {
|
||||
Assert.notNull(prefix, "prefix is null");
|
||||
if (XMLConstants.XML_NS_PREFIX.equals(prefix)) {
|
||||
return XMLConstants.XML_NS_URI;
|
||||
}
|
||||
else if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) {
|
||||
return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
|
||||
}
|
||||
else if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
|
||||
return defaultNamespaceUri;
|
||||
}
|
||||
else if (prefixToNamespaceUri.containsKey(prefix)) {
|
||||
return (String) prefixToNamespaceUri.get(prefix);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getPrefix(String namespaceUri) {
|
||||
List prefixes = getPrefixesInternal(namespaceUri);
|
||||
return prefixes.isEmpty() ? null : (String) prefixes.get(0);
|
||||
}
|
||||
|
||||
public Iterator getPrefixes(String namespaceUri) {
|
||||
return getPrefixesInternal(namespaceUri).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bindings for this namespace context. The supplied map must consist of string key value pairs.
|
||||
*
|
||||
* @param bindings the bindings
|
||||
*/
|
||||
public void setBindings(Map bindings) {
|
||||
for (Iterator iterator = bindings.keySet().iterator(); iterator.hasNext();) {
|
||||
String prefix = (String) iterator.next();
|
||||
bindNamespaceUri(prefix, (String) bindings.get(prefix));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the given namespace as default namespace.
|
||||
*
|
||||
* @param namespaceUri the namespace uri
|
||||
*/
|
||||
public void bindDefaultNamespaceUri(String namespaceUri) {
|
||||
bindNamespaceUri(XMLConstants.DEFAULT_NS_PREFIX, namespaceUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the given prefix to the given namespace.
|
||||
*
|
||||
* @param prefix the namespace prefix
|
||||
* @param namespaceUri the namespace uri
|
||||
*/
|
||||
public void bindNamespaceUri(String prefix, String namespaceUri) {
|
||||
Assert.notNull(prefix, "No prefix given");
|
||||
Assert.notNull(namespaceUri, "No namespaceUri given");
|
||||
if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
|
||||
defaultNamespaceUri = namespaceUri;
|
||||
}
|
||||
else {
|
||||
prefixToNamespaceUri.put(prefix, namespaceUri);
|
||||
getPrefixesInternal(namespaceUri).add(prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all declared prefixes.
|
||||
*/
|
||||
public void clear() {
|
||||
prefixToNamespaceUri.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all declared prefixes.
|
||||
*
|
||||
* @return the declared prefixes
|
||||
*/
|
||||
public Iterator getBoundPrefixes() {
|
||||
return prefixToNamespaceUri.keySet().iterator();
|
||||
}
|
||||
|
||||
private List getPrefixesInternal(String namespaceUri) {
|
||||
if (defaultNamespaceUri.equals(namespaceUri)) {
|
||||
return Collections.singletonList(XMLConstants.DEFAULT_NS_PREFIX);
|
||||
}
|
||||
else if (XMLConstants.XML_NS_URI.equals(namespaceUri)) {
|
||||
return Collections.singletonList(XMLConstants.XML_NS_PREFIX);
|
||||
}
|
||||
else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceUri)) {
|
||||
return Collections.singletonList(XMLConstants.XMLNS_ATTRIBUTE);
|
||||
}
|
||||
else {
|
||||
List list = (List) namespaceUriToPrefixes.get(namespaceUri);
|
||||
if (list == null) {
|
||||
list = new ArrayList();
|
||||
namespaceUriToPrefixes.put(namespaceUri, list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given prefix from this context.
|
||||
*
|
||||
* @param prefix the prefix to be removed
|
||||
*/
|
||||
public void removeBinding(String prefix) {
|
||||
if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
|
||||
defaultNamespaceUri = "";
|
||||
}
|
||||
else {
|
||||
String namespaceUri = (String) namespaceUriToPrefixes.get(prefix);
|
||||
List prefixes = getPrefixesInternal(namespaceUri);
|
||||
prefixes.remove(prefix);
|
||||
namespaceUriToPrefixes.remove(prefixes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides classes that help with XML Namespace processing. Mostly for internal use by the framework.
|
||||
</body>
|
||||
</html>
|
||||
6
xml/src/main/java/org/springframework/xml/package.html
Normal file
6
xml/src/main/java/org/springframework/xml/package.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides classes for XML handling: version detection and a base XML exception class. Mostly for internal use by the
|
||||
framework.
|
||||
</body>
|
||||
</html>
|
||||
57
xml/src/main/java/org/springframework/xml/sax/SaxUtils.java
Normal file
57
xml/src/main/java/org/springframework/xml/sax/SaxUtils.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.sax;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public abstract class SaxUtils {
|
||||
|
||||
/**
|
||||
* Creates a SAX <code>InputSource</code> from the given resource. Sets the system identifier to the resource's
|
||||
* <code>URL</code>, if available.
|
||||
*
|
||||
* @param resource the resource
|
||||
* @return the input source created from the resource
|
||||
* @throws IOException if an I/O exception occurs
|
||||
* @see InputSource#setSystemId(String)
|
||||
* @see #getSystemId(org.springframework.core.io.Resource)
|
||||
*/
|
||||
public static InputSource createInputSource(Resource resource) throws IOException {
|
||||
InputSource inputSource = new InputSource(resource.getInputStream());
|
||||
inputSource.setSystemId(getSystemId(resource));
|
||||
return inputSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the URL from the given resource as System ID. Returns <code>null</code> if it cannot be openened.
|
||||
*/
|
||||
public static String getSystemId(Resource resource) {
|
||||
try {
|
||||
return resource.getURL().toString();
|
||||
}
|
||||
catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides classes that help with SAX: the Simple API for XML. Mostly for internal use by the framework.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.stream;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLStreamConstants;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Abstract base class for <code>XMLStreamReader</code>s.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public abstract class AbstractXmlStreamReader implements XMLStreamReader {
|
||||
|
||||
public String getElementText() throws XMLStreamException {
|
||||
if (getEventType() != XMLStreamConstants.START_ELEMENT) {
|
||||
throw new XMLStreamException("parser must be on START_ELEMENT to read next text", getLocation());
|
||||
}
|
||||
int eventType = next();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
while (eventType != XMLStreamConstants.END_ELEMENT) {
|
||||
if (eventType == XMLStreamConstants.CHARACTERS || eventType == XMLStreamConstants.CDATA ||
|
||||
eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.ENTITY_REFERENCE) {
|
||||
buffer.append(getText());
|
||||
}
|
||||
else
|
||||
if (eventType == XMLStreamConstants.PROCESSING_INSTRUCTION || eventType == XMLStreamConstants.COMMENT) {
|
||||
// skipping
|
||||
}
|
||||
else if (eventType == XMLStreamConstants.END_DOCUMENT) {
|
||||
throw new XMLStreamException("unexpected end of document when reading element text content",
|
||||
getLocation());
|
||||
}
|
||||
else if (eventType == XMLStreamConstants.START_ELEMENT) {
|
||||
throw new XMLStreamException("element text content may not contain START_ELEMENT", getLocation());
|
||||
}
|
||||
else {
|
||||
throw new XMLStreamException("Unexpected event type " + eventType, getLocation());
|
||||
}
|
||||
eventType = next();
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public String getAttributeLocalName(int index) {
|
||||
return getAttributeName(index).getLocalPart();
|
||||
}
|
||||
|
||||
public String getAttributeNamespace(int index) {
|
||||
return getAttributeName(index).getNamespaceURI();
|
||||
}
|
||||
|
||||
public String getAttributePrefix(int index) {
|
||||
return getAttributeName(index).getPrefix();
|
||||
}
|
||||
|
||||
public String getNamespaceURI() {
|
||||
int eventType = getEventType();
|
||||
if (eventType == XMLStreamConstants.START_ELEMENT || eventType == XMLStreamConstants.END_ELEMENT) {
|
||||
return getName().getNamespaceURI();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("parser must be on START_ELEMENT or END_ELEMENT state");
|
||||
}
|
||||
}
|
||||
|
||||
public String getNamespaceURI(String prefix) {
|
||||
Assert.notNull(prefix, "No prefix given");
|
||||
return getNamespaceContext().getNamespaceURI(prefix);
|
||||
}
|
||||
|
||||
public boolean hasText() {
|
||||
int eventType = getEventType();
|
||||
return eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.CHARACTERS ||
|
||||
eventType == XMLStreamConstants.COMMENT || eventType == XMLStreamConstants.CDATA ||
|
||||
eventType == XMLStreamConstants.ENTITY_REFERENCE;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
int eventType = getEventType();
|
||||
if (eventType == XMLStreamConstants.START_ELEMENT || eventType == XMLStreamConstants.END_ELEMENT) {
|
||||
return getName().getPrefix();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("parser must be on START_ELEMENT or END_ELEMENT state");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasName() {
|
||||
int eventType = getEventType();
|
||||
return eventType == XMLStreamConstants.START_ELEMENT || eventType == XMLStreamConstants.END_ELEMENT;
|
||||
}
|
||||
|
||||
public boolean isWhiteSpace() {
|
||||
return getEventType() == XMLStreamConstants.SPACE;
|
||||
}
|
||||
|
||||
public boolean isStartElement() {
|
||||
return getEventType() == XMLStreamConstants.START_ELEMENT;
|
||||
}
|
||||
|
||||
public boolean isEndElement() {
|
||||
return getEventType() == XMLStreamConstants.END_ELEMENT;
|
||||
}
|
||||
|
||||
public boolean isCharacters() {
|
||||
return getEventType() == XMLStreamConstants.CHARACTERS;
|
||||
}
|
||||
|
||||
public int nextTag() throws XMLStreamException {
|
||||
int eventType = next();
|
||||
while (eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace() ||
|
||||
eventType == XMLStreamConstants.CDATA && isWhiteSpace() || 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 expectedType, String namespaceURI, String localName) throws XMLStreamException {
|
||||
int eventType = getEventType();
|
||||
if (eventType != expectedType) {
|
||||
throw new XMLStreamException("Expected [" + expectedType + "] but read [" + eventType + "]");
|
||||
}
|
||||
}
|
||||
|
||||
public String getAttributeValue(String namespaceURI, String localName) {
|
||||
for (int i = 0; i < getAttributeCount(); i++) {
|
||||
QName name = getAttributeName(i);
|
||||
if (name.getNamespaceURI().equals(namespaceURI) && name.getLocalPart().equals(localName)) {
|
||||
return getAttributeValue(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasNext() throws XMLStreamException {
|
||||
return getEventType() != END_DOCUMENT;
|
||||
}
|
||||
|
||||
public String getLocalName() {
|
||||
return getName().getLocalPart();
|
||||
}
|
||||
|
||||
public char[] getTextCharacters() {
|
||||
return getText().toCharArray();
|
||||
}
|
||||
|
||||
public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length)
|
||||
throws XMLStreamException {
|
||||
char[] source = getTextCharacters();
|
||||
length = Math.min(length, source.length);
|
||||
System.arraycopy(source, sourceStart, target, targetStart, length);
|
||||
return length;
|
||||
}
|
||||
|
||||
public int getTextLength() {
|
||||
return getText().length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.stream;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import org.springframework.xml.namespace.QNameUtils;
|
||||
import org.springframework.xml.namespace.SimpleNamespaceContext;
|
||||
|
||||
/**
|
||||
* Abstract base class for SAX <code>ContentHandler</code> implementations that use StAX as a basis. All methods
|
||||
* delegate to internal template methods, capable of throwing a <code>XMLStreamException</code>. Additionally, an
|
||||
* namespace context is used to keep track of declared namespaces.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public abstract class StaxContentHandler implements ContentHandler {
|
||||
|
||||
private SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
|
||||
|
||||
/**
|
||||
* @throws SAXException
|
||||
*/
|
||||
public final void startDocument() throws SAXException {
|
||||
namespaceContext.clear();
|
||||
try {
|
||||
startDocumentInternal();
|
||||
}
|
||||
catch (XMLStreamException ex) {
|
||||
throw new SAXException("Could not handle startDocument: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void startDocumentInternal() throws XMLStreamException;
|
||||
|
||||
public final void endDocument() throws SAXException {
|
||||
namespaceContext.clear();
|
||||
try {
|
||||
endDocumentInternal();
|
||||
}
|
||||
catch (XMLStreamException ex) {
|
||||
throw new SAXException("Could not handle startDocument: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void endDocumentInternal() throws XMLStreamException;
|
||||
|
||||
/**
|
||||
* Binds the given prefix to the given namespaces.
|
||||
*
|
||||
* @see SimpleNamespaceContext#bindNamespaceUri(String, String)
|
||||
*/
|
||||
public final void startPrefixMapping(String prefix, String uri) {
|
||||
namespaceContext.bindNamespaceUri(prefix, uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the binding for the given prefix.
|
||||
*
|
||||
* @see SimpleNamespaceContext#removeBinding(String)
|
||||
*/
|
||||
public final void endPrefixMapping(String prefix) {
|
||||
namespaceContext.removeBinding(prefix);
|
||||
}
|
||||
|
||||
public final void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
|
||||
try {
|
||||
startElementInternal(QNameUtils.toQName(uri, qName), atts, namespaceContext);
|
||||
}
|
||||
catch (XMLStreamException ex) {
|
||||
throw new SAXException("Could not handle startElement: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void startElementInternal(QName name, Attributes atts, SimpleNamespaceContext namespaceContext)
|
||||
throws XMLStreamException;
|
||||
|
||||
public final void endElement(String uri, String localName, String qName) throws SAXException {
|
||||
try {
|
||||
endElementInternal(QNameUtils.toQName(uri, qName), namespaceContext);
|
||||
}
|
||||
catch (XMLStreamException ex) {
|
||||
throw new SAXException("Could not handle endElement: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void endElementInternal(QName name, SimpleNamespaceContext namespaceContext)
|
||||
throws XMLStreamException;
|
||||
|
||||
public final void characters(char ch[], int start, int length) throws SAXException {
|
||||
try {
|
||||
charactersInternal(ch, start, length);
|
||||
}
|
||||
catch (XMLStreamException ex) {
|
||||
throw new SAXException("Could not handle characters: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void charactersInternal(char[] ch, int start, int length) throws XMLStreamException;
|
||||
|
||||
public final void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
|
||||
try {
|
||||
ignorableWhitespaceInternal(ch, start, length);
|
||||
}
|
||||
catch (XMLStreamException ex) {
|
||||
throw new SAXException("Could not handle ignorableWhitespace:" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void ignorableWhitespaceInternal(char[] ch, int start, int length) throws XMLStreamException;
|
||||
|
||||
public final void processingInstruction(String target, String data) throws SAXException {
|
||||
try {
|
||||
processingInstructionInternal(target, data);
|
||||
}
|
||||
catch (XMLStreamException ex) {
|
||||
throw new SAXException("Could not handle processingInstruction: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void processingInstructionInternal(String target, String data) throws XMLStreamException;
|
||||
|
||||
public final void skippedEntity(String name) throws SAXException {
|
||||
try {
|
||||
skippedEntityInternal(name);
|
||||
}
|
||||
catch (XMLStreamException ex) {
|
||||
throw new SAXException("Could not handle skippedEntity: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void skippedEntityInternal(String name) throws XMLStreamException;
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.stream;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.Location;
|
||||
import javax.xml.stream.XMLEventFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
import javax.xml.stream.util.XMLEventConsumer;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.xml.namespace.QNameUtils;
|
||||
import org.springframework.xml.namespace.SimpleNamespaceContext;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.Locator;
|
||||
|
||||
/**
|
||||
* SAX <code>ContentHandler</code> that transforms callback calls to <code>XMLEvent</code>s and writes them to a
|
||||
* <code>XMLEventConsumer</code>.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see XMLEvent
|
||||
* @see XMLEventConsumer
|
||||
*/
|
||||
public class StaxEventContentHandler extends StaxContentHandler {
|
||||
|
||||
private final XMLEventFactory eventFactory;
|
||||
|
||||
private final XMLEventConsumer eventConsumer;
|
||||
|
||||
private Locator locator;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>StaxEventContentHandler</code> that writes to the given
|
||||
* <code>XMLEventConsumer</code>. A default <code>XMLEventFactory</code> will be created.
|
||||
*
|
||||
* @param consumer the consumer to write events to
|
||||
*/
|
||||
public StaxEventContentHandler(XMLEventConsumer consumer) {
|
||||
eventFactory = XMLEventFactory.newInstance();
|
||||
eventConsumer = consumer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>StaxEventContentHandler</code> that uses the given event factory to create
|
||||
* events and writes to the given <code>XMLEventConsumer</code>.
|
||||
*
|
||||
* @param consumer the consumer to write events to
|
||||
* @param factory the factory used to create events
|
||||
*/
|
||||
public StaxEventContentHandler(XMLEventConsumer consumer, XMLEventFactory factory) {
|
||||
eventFactory = factory;
|
||||
eventConsumer = consumer;
|
||||
}
|
||||
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
this.locator = locator;
|
||||
}
|
||||
|
||||
protected void startDocumentInternal() throws XMLStreamException {
|
||||
consumeEvent(eventFactory.createStartDocument());
|
||||
}
|
||||
|
||||
protected void endDocumentInternal() throws XMLStreamException {
|
||||
consumeEvent(eventFactory.createEndDocument());
|
||||
}
|
||||
|
||||
protected void startElementInternal(QName name, Attributes atts, SimpleNamespaceContext namespaceContext)
|
||||
throws XMLStreamException {
|
||||
List attributes = getAttributes(atts);
|
||||
List namespaces = createNamespaces(namespaceContext);
|
||||
consumeEvent(eventFactory.createStartElement(name, attributes.iterator(), namespaces.iterator()));
|
||||
}
|
||||
|
||||
protected void endElementInternal(QName name, SimpleNamespaceContext namespaceContext) throws XMLStreamException {
|
||||
List namespaces = createNamespaces(namespaceContext);
|
||||
consumeEvent(eventFactory.createEndElement(name, namespaces.iterator()));
|
||||
}
|
||||
|
||||
protected void charactersInternal(char[] ch, int start, int length) throws XMLStreamException {
|
||||
consumeEvent(eventFactory.createCharacters(new String(ch, start, length)));
|
||||
}
|
||||
|
||||
protected void ignorableWhitespaceInternal(char[] ch, int start, int length) throws XMLStreamException {
|
||||
consumeEvent(eventFactory.createIgnorableSpace(new String(ch, start, length)));
|
||||
}
|
||||
|
||||
protected void processingInstructionInternal(String target, String data) throws XMLStreamException {
|
||||
consumeEvent(eventFactory.createProcessingInstruction(target, data));
|
||||
}
|
||||
|
||||
private void consumeEvent(XMLEvent event) throws XMLStreamException {
|
||||
if (locator != null) {
|
||||
eventFactory.setLocation(new SaxLocation(locator));
|
||||
}
|
||||
eventConsumer.add(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a list of <code>NameSpace</code> objects from the <code>NamespaceContext</code>.
|
||||
*/
|
||||
private List createNamespaces(SimpleNamespaceContext namespaceContext) {
|
||||
List namespaces = new ArrayList();
|
||||
String defaultNamespaceUri = namespaceContext.getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX);
|
||||
if (StringUtils.hasLength(defaultNamespaceUri)) {
|
||||
namespaces.add(eventFactory.createNamespace(defaultNamespaceUri));
|
||||
}
|
||||
for (Iterator iterator = namespaceContext.getBoundPrefixes(); iterator.hasNext();) {
|
||||
String prefix = (String) iterator.next();
|
||||
String namespaceUri = namespaceContext.getNamespaceURI(prefix);
|
||||
namespaces.add(eventFactory.createNamespace(prefix, namespaceUri));
|
||||
}
|
||||
return namespaces;
|
||||
}
|
||||
|
||||
private List getAttributes(Attributes attributes) {
|
||||
List list = new ArrayList();
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
QName name = QNameUtils.toQName(attributes.getURI(i), attributes.getQName(i));
|
||||
if (!("xmlns".equals(name.getLocalPart()) || "xmlns".equals(QNameUtils.getPrefix(name)))) {
|
||||
list.add(eventFactory.createAttribute(name, attributes.getValue(i)));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
//
|
||||
// No operation
|
||||
//
|
||||
|
||||
protected void skippedEntityInternal(String name) throws XMLStreamException {
|
||||
}
|
||||
|
||||
private static class SaxLocation implements Location {
|
||||
|
||||
private Locator locator;
|
||||
|
||||
public SaxLocation(Locator locator) {
|
||||
this.locator = locator;
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return locator.getLineNumber();
|
||||
}
|
||||
|
||||
public int getColumnNumber() {
|
||||
return locator.getColumnNumber();
|
||||
}
|
||||
|
||||
public int getCharacterOffset() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public String getPublicId() {
|
||||
return locator.getPublicId();
|
||||
}
|
||||
|
||||
public String getSystemId() {
|
||||
return locator.getSystemId();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.stream;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLStreamConstants;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.Attribute;
|
||||
import javax.xml.stream.events.Characters;
|
||||
import javax.xml.stream.events.EndElement;
|
||||
import javax.xml.stream.events.Namespace;
|
||||
import javax.xml.stream.events.NotationDeclaration;
|
||||
import javax.xml.stream.events.ProcessingInstruction;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.AttributesImpl;
|
||||
|
||||
import org.springframework.xml.namespace.QNameUtils;
|
||||
|
||||
/**
|
||||
* SAX <code>XMLReader</code> that reads from a StAX <code>XMLEventReader</code>. Consumes <code>XMLEvents</code> from
|
||||
* an <code>XMLEventReader</code>, and calls the corresponding methods on the SAX callback interfaces.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see XMLEventReader
|
||||
* @see #setContentHandler(org.xml.sax.ContentHandler)
|
||||
* @see #setDTDHandler(org.xml.sax.DTDHandler)
|
||||
* @see #setEntityResolver(org.xml.sax.EntityResolver)
|
||||
* @see #setErrorHandler(org.xml.sax.ErrorHandler)
|
||||
*/
|
||||
public class StaxEventXmlReader extends StaxXmlReader {
|
||||
|
||||
private final XMLEventReader reader;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>StaxEventXmlReader</code> that reads from the given
|
||||
* <code>XMLEventReader</code>. The supplied event reader must be in <code>XMLStreamConstants.START_DOCUMENT</code>
|
||||
* or <code>XMLStreamConstants.START_ELEMENT</code> state.
|
||||
*
|
||||
* @param reader the <code>XMLEventReader</code> to read from
|
||||
* @throws IllegalStateException if the reader is not at the start of a document or element
|
||||
*/
|
||||
public StaxEventXmlReader(XMLEventReader reader) {
|
||||
try {
|
||||
XMLEvent event = reader.peek();
|
||||
if (event == null || !(event.isStartDocument() || event.isStartElement())) {
|
||||
throw new IllegalStateException("XMLEventReader not at start of document or element");
|
||||
}
|
||||
}
|
||||
catch (XMLStreamException ex) {
|
||||
throw new IllegalStateException("Could not read first element: " + ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
protected void parseInternal() throws SAXException, XMLStreamException {
|
||||
boolean documentEnded = false;
|
||||
while (reader.hasNext()) {
|
||||
XMLEvent event = reader.nextEvent();
|
||||
switch (event.getEventType()) {
|
||||
case XMLStreamConstants.START_ELEMENT:
|
||||
handleStartElement(event.asStartElement());
|
||||
break;
|
||||
case XMLStreamConstants.END_ELEMENT:
|
||||
handleEndElement(event.asEndElement());
|
||||
break;
|
||||
case XMLStreamConstants.PROCESSING_INSTRUCTION:
|
||||
handleProcessingInstruction((ProcessingInstruction) event);
|
||||
break;
|
||||
case XMLStreamConstants.CHARACTERS:
|
||||
case XMLStreamConstants.SPACE:
|
||||
case XMLStreamConstants.CDATA:
|
||||
handleCharacters(event.asCharacters());
|
||||
break;
|
||||
case XMLStreamConstants.START_DOCUMENT:
|
||||
setLocator(event.getLocation());
|
||||
handleStartDocument();
|
||||
break;
|
||||
case XMLStreamConstants.END_DOCUMENT:
|
||||
handleEndDocument();
|
||||
documentEnded = true;
|
||||
break;
|
||||
case XMLStreamConstants.NOTATION_DECLARATION:
|
||||
handleNotationDeclaration((NotationDeclaration) event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!documentEnded) {
|
||||
handleEndDocument();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void handleCharacters(Characters characters) throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
if (characters.isIgnorableWhiteSpace()) {
|
||||
getContentHandler()
|
||||
.ignorableWhitespace(characters.getData().toCharArray(), 0, characters.getData().length());
|
||||
}
|
||||
else {
|
||||
getContentHandler().characters(characters.getData().toCharArray(), 0, characters.getData().length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleEndDocument() throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
getContentHandler().endDocument();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleEndElement(EndElement endElement) throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
getContentHandler().endElement(endElement.getName().getNamespaceURI(), endElement.getName().getLocalPart(),
|
||||
QNameUtils.toQualifiedName(endElement.getName()));
|
||||
|
||||
for (Iterator i = endElement.getNamespaces(); i.hasNext();) {
|
||||
Namespace namespace = (Namespace) i.next();
|
||||
getContentHandler().endPrefixMapping(namespace.getPrefix());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNotationDeclaration(NotationDeclaration declaration) throws SAXException {
|
||||
if (getDtdHandler() != null) {
|
||||
getDtdHandler().notationDecl(declaration.getName(), declaration.getPublicId(), declaration.getSystemId());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleProcessingInstruction(ProcessingInstruction pi) throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
getContentHandler().processingInstruction(pi.getTarget(), pi.getData());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleStartDocument() throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
getContentHandler().startDocument();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleStartElement(StartElement startElement) throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
for (Iterator i = startElement.getNamespaces(); i.hasNext();) {
|
||||
Namespace namespace = (Namespace) i.next();
|
||||
getContentHandler().startPrefixMapping(namespace.getPrefix(), namespace.getNamespaceURI());
|
||||
}
|
||||
|
||||
getContentHandler().startElement(startElement.getName().getNamespaceURI(),
|
||||
startElement.getName().getLocalPart(), QNameUtils.toQualifiedName(startElement.getName()),
|
||||
getAttributes(startElement));
|
||||
}
|
||||
}
|
||||
|
||||
private Attributes getAttributes(StartElement event) {
|
||||
AttributesImpl attributes = new AttributesImpl();
|
||||
|
||||
for (Iterator i = event.getAttributes(); i.hasNext();) {
|
||||
Attribute attribute = (Attribute) i.next();
|
||||
attributes.addAttribute(attribute.getName().getNamespaceURI(), attribute.getName().getLocalPart(),
|
||||
QNameUtils.toQualifiedName(attribute.getName()), attribute.getDTDType(), attribute.getValue());
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.stream;
|
||||
|
||||
import java.util.Iterator;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.xml.namespace.QNameUtils;
|
||||
import org.springframework.xml.namespace.SimpleNamespaceContext;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.Locator;
|
||||
|
||||
/**
|
||||
* SAX <code>ContentHandler</code> that writes to a <code>XMLStreamWriter</code>.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see XMLStreamWriter
|
||||
*/
|
||||
public class StaxStreamContentHandler extends StaxContentHandler {
|
||||
|
||||
private final XMLStreamWriter streamWriter;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>StaxStreamContentHandler</code> that writes to the given
|
||||
* <code>XMLStreamWriter</code>.
|
||||
*
|
||||
* @param streamWriter the stream writer to write to
|
||||
*/
|
||||
public StaxStreamContentHandler(XMLStreamWriter streamWriter) {
|
||||
this.streamWriter = streamWriter;
|
||||
}
|
||||
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
}
|
||||
|
||||
protected void charactersInternal(char[] ch, int start, int length) throws XMLStreamException {
|
||||
streamWriter.writeCharacters(ch, start, length);
|
||||
}
|
||||
|
||||
protected void endDocumentInternal() throws XMLStreamException {
|
||||
streamWriter.writeEndDocument();
|
||||
}
|
||||
|
||||
protected void endElementInternal(QName name, SimpleNamespaceContext namespaceContext) throws XMLStreamException {
|
||||
streamWriter.writeEndElement();
|
||||
}
|
||||
|
||||
protected void ignorableWhitespaceInternal(char[] ch, int start, int length) throws XMLStreamException {
|
||||
streamWriter.writeCharacters(ch, start, length);
|
||||
}
|
||||
|
||||
protected void processingInstructionInternal(String target, String data) throws XMLStreamException {
|
||||
streamWriter.writeProcessingInstruction(target, data);
|
||||
}
|
||||
|
||||
protected void skippedEntityInternal(String name) {
|
||||
}
|
||||
|
||||
protected void startDocumentInternal() throws XMLStreamException {
|
||||
streamWriter.writeStartDocument();
|
||||
}
|
||||
|
||||
protected void startElementInternal(QName name, Attributes attributes, SimpleNamespaceContext namespaceContext)
|
||||
throws XMLStreamException {
|
||||
streamWriter.writeStartElement(QNameUtils.getPrefix(name), name.getLocalPart(), name.getNamespaceURI());
|
||||
String defaultNamespaceUri = namespaceContext.getNamespaceURI("");
|
||||
if (StringUtils.hasLength(defaultNamespaceUri)) {
|
||||
streamWriter.writeNamespace("", defaultNamespaceUri);
|
||||
streamWriter.setDefaultNamespace(defaultNamespaceUri);
|
||||
}
|
||||
for (Iterator iterator = namespaceContext.getBoundPrefixes(); iterator.hasNext();) {
|
||||
String prefix = (String) iterator.next();
|
||||
streamWriter.writeNamespace(prefix, namespaceContext.getNamespaceURI(prefix));
|
||||
streamWriter.setPrefix(prefix, namespaceContext.getNamespaceURI(prefix));
|
||||
}
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
QName attrName = QNameUtils.toQName(attributes.getURI(i), attributes.getQName(i));
|
||||
String attrPrefix = QNameUtils.getPrefix(attrName);
|
||||
if (!("xmlns".equals(attrName.getLocalPart()) || "xmlns".equals(attrPrefix))) {
|
||||
streamWriter.writeAttribute(attrPrefix, attrName.getNamespaceURI(), attrName.getLocalPart(),
|
||||
attributes.getValue(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.stream;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLStreamConstants;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
|
||||
import org.springframework.xml.namespace.QNameUtils;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.AttributesImpl;
|
||||
|
||||
/**
|
||||
* SAX <code>XMLReader</code> that reads from a StAX <code>XMLStreamReader</code>. Reads from an
|
||||
* <code>XMLStreamReader</code>, and calls the corresponding methods on the SAX callback interfaces.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see XMLStreamReader
|
||||
* @see #setContentHandler(org.xml.sax.ContentHandler)
|
||||
* @see #setDTDHandler(org.xml.sax.DTDHandler)
|
||||
* @see #setEntityResolver(org.xml.sax.EntityResolver)
|
||||
* @see #setErrorHandler(org.xml.sax.ErrorHandler)
|
||||
*/
|
||||
public class StaxStreamXmlReader extends StaxXmlReader {
|
||||
|
||||
private final XMLStreamReader reader;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>StaxStreamXmlReader</code> that reads from the given
|
||||
* <code>XMLStreamReader</code>. The supplied stream reader must be in <code>XMLStreamConstants.START_DOCUMENT</code>
|
||||
* or <code>XMLStreamConstants.START_ELEMENT</code> state.
|
||||
*
|
||||
* @param reader the <code>XMLEventReader</code> to read from
|
||||
* @throws IllegalStateException if the reader is not at the start of a document or element
|
||||
*/
|
||||
public StaxStreamXmlReader(XMLStreamReader reader) {
|
||||
int event = reader.getEventType();
|
||||
if (!(event == XMLStreamConstants.START_DOCUMENT || event == XMLStreamConstants.START_ELEMENT)) {
|
||||
throw new IllegalStateException("XMLEventReader not at start of document or element");
|
||||
}
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
protected void parseInternal() throws SAXException, XMLStreamException {
|
||||
boolean documentEnded = false;
|
||||
while (true) {
|
||||
switch (reader.getEventType()) {
|
||||
case XMLStreamConstants.START_ELEMENT:
|
||||
handleStartElement();
|
||||
break;
|
||||
case XMLStreamConstants.END_ELEMENT:
|
||||
handleEndElement();
|
||||
break;
|
||||
case XMLStreamConstants.PROCESSING_INSTRUCTION:
|
||||
handleProcessingInstruction();
|
||||
break;
|
||||
case XMLStreamConstants.CHARACTERS:
|
||||
case XMLStreamConstants.SPACE:
|
||||
case XMLStreamConstants.CDATA:
|
||||
handleCharacters();
|
||||
break;
|
||||
case XMLStreamConstants.START_DOCUMENT:
|
||||
handleStartDocument();
|
||||
break;
|
||||
case XMLStreamConstants.END_DOCUMENT:
|
||||
handleEndDocument();
|
||||
documentEnded = true;
|
||||
break;
|
||||
}
|
||||
if (reader.hasNext()) {
|
||||
reader.next();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!documentEnded) {
|
||||
handleEndDocument();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void handleCharacters() throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
if (reader.isWhiteSpace()) {
|
||||
getContentHandler()
|
||||
.ignorableWhitespace(reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength());
|
||||
}
|
||||
else {
|
||||
getContentHandler()
|
||||
.characters(reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleEndDocument() throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
getContentHandler().endDocument();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleEndElement() throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
QName qName = reader.getName();
|
||||
getContentHandler()
|
||||
.endElement(qName.getNamespaceURI(), qName.getLocalPart(), QNameUtils.toQualifiedName(qName));
|
||||
for (int i = 0; i < reader.getNamespaceCount(); i++) {
|
||||
String prefix = reader.getNamespacePrefix(i);
|
||||
if (prefix == null) {
|
||||
prefix = "";
|
||||
}
|
||||
getContentHandler().endPrefixMapping(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleProcessingInstruction() throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
getContentHandler().processingInstruction(reader.getPITarget(), reader.getPIData());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleStartDocument() throws SAXException {
|
||||
setLocator(reader.getLocation());
|
||||
if (getContentHandler() != null) {
|
||||
getContentHandler().startDocument();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleStartElement() throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
for (int i = 0; i < reader.getNamespaceCount(); i++) {
|
||||
String prefix = reader.getNamespacePrefix(i);
|
||||
if (prefix == null) {
|
||||
prefix = "";
|
||||
}
|
||||
getContentHandler().startPrefixMapping(prefix, reader.getNamespaceURI(i));
|
||||
}
|
||||
|
||||
QName qName = reader.getName();
|
||||
getContentHandler().startElement(qName.getNamespaceURI(),
|
||||
qName.getLocalPart(),
|
||||
QNameUtils.toQualifiedName(qName),
|
||||
getAttributes());
|
||||
}
|
||||
}
|
||||
|
||||
private Attributes getAttributes() {
|
||||
AttributesImpl attributes = new AttributesImpl();
|
||||
|
||||
for (int i = 0; i < reader.getAttributeCount(); i++) {
|
||||
String namespace = reader.getAttributeNamespace(i);
|
||||
if (namespace == null) {
|
||||
namespace = "";
|
||||
}
|
||||
String type = reader.getAttributeType(i);
|
||||
if (type == null) {
|
||||
type = "";
|
||||
}
|
||||
attributes.addAttribute(namespace,
|
||||
reader.getAttributeLocalName(i),
|
||||
QNameUtils.toQualifiedName(reader.getAttributeName(i)),
|
||||
type,
|
||||
reader.getAttributeValue(i));
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.stream;
|
||||
|
||||
import javax.xml.stream.Location;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.DTDHandler;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXNotRecognizedException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
/**
|
||||
* Abstract base class for SAX <code>XMLReader</code> implementations that use StAX as a basis.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #setContentHandler(org.xml.sax.ContentHandler)
|
||||
* @see #setDTDHandler(org.xml.sax.DTDHandler)
|
||||
* @see #setEntityResolver(org.xml.sax.EntityResolver)
|
||||
* @see #setErrorHandler(org.xml.sax.ErrorHandler)
|
||||
*/
|
||||
public abstract class StaxXmlReader implements XMLReader {
|
||||
|
||||
private DTDHandler dtdHandler;
|
||||
|
||||
private ContentHandler contentHandler;
|
||||
|
||||
private EntityResolver entityResolver;
|
||||
|
||||
private ErrorHandler errorHandler;
|
||||
|
||||
public ContentHandler getContentHandler() {
|
||||
return contentHandler;
|
||||
}
|
||||
|
||||
public void setContentHandler(ContentHandler contentHandler) {
|
||||
this.contentHandler = contentHandler;
|
||||
}
|
||||
|
||||
public DTDHandler getDtdHandler() {
|
||||
return dtdHandler;
|
||||
}
|
||||
|
||||
public void setDtdHandler(DTDHandler dtdHandler) {
|
||||
this.dtdHandler = dtdHandler;
|
||||
}
|
||||
|
||||
public EntityResolver getEntityResolver() {
|
||||
return entityResolver;
|
||||
}
|
||||
|
||||
public void setEntityResolver(EntityResolver entityResolver) {
|
||||
this.entityResolver = entityResolver;
|
||||
}
|
||||
|
||||
public ErrorHandler getErrorHandler() {
|
||||
return errorHandler;
|
||||
}
|
||||
|
||||
public void setErrorHandler(ErrorHandler errorHandler) {
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a <code>SAXNotRecognizedException</code> exception.
|
||||
*
|
||||
* @throws SAXNotRecognizedException always
|
||||
*/
|
||||
public boolean getFeature(String name) throws SAXNotRecognizedException {
|
||||
throw new SAXNotRecognizedException(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a <code>SAXNotRecognizedException</code> exception.
|
||||
*
|
||||
* @throws SAXNotRecognizedException always
|
||||
*/
|
||||
public void setFeature(String name, boolean value) throws SAXNotRecognizedException {
|
||||
throw new SAXNotRecognizedException(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a <code>SAXNotRecognizedException</code> exception.
|
||||
*
|
||||
* @throws SAXNotRecognizedException always
|
||||
*/
|
||||
public Object getProperty(String name) throws SAXNotRecognizedException {
|
||||
throw new SAXNotRecognizedException(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a <code>SAXNotRecognizedException</code> exception.
|
||||
*
|
||||
* @throws SAXNotRecognizedException always
|
||||
*/
|
||||
public void setProperty(String name, Object value) throws SAXNotRecognizedException {
|
||||
throw new SAXNotRecognizedException(name);
|
||||
}
|
||||
|
||||
public void setDTDHandler(DTDHandler dtdHandler) {
|
||||
this.setDtdHandler(dtdHandler);
|
||||
}
|
||||
|
||||
public DTDHandler getDTDHandler() {
|
||||
return getDtdHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the StAX XML reader passed at construction-time.
|
||||
* <p/>
|
||||
* <strong>Note</strong> that the given <code>InputSource</code> is not read, but ignored.
|
||||
*
|
||||
* @param ignored is ignored
|
||||
* @throws SAXException A SAX exception, possibly wrapping a <code>XMLStreamException</code>
|
||||
*/
|
||||
public final void parse(InputSource ignored) throws SAXException {
|
||||
parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the StAX XML reader passed at construction-time.
|
||||
* <p/>
|
||||
* <strong>Note</strong> that the given system identifier is not read, but ignored.
|
||||
*
|
||||
* @param ignored is ignored
|
||||
* @throws SAXException A SAX exception, possibly wrapping a <code>XMLStreamException</code>
|
||||
*/
|
||||
public final void parse(String ignored) throws SAXException {
|
||||
parse();
|
||||
}
|
||||
|
||||
private void parse() throws SAXException {
|
||||
try {
|
||||
parseInternal();
|
||||
}
|
||||
catch (XMLStreamException ex) {
|
||||
SAXParseException saxException = new SAXParseException(ex.getMessage(), null, null,
|
||||
ex.getLocation().getLineNumber(), ex.getLocation().getColumnNumber(), ex);
|
||||
if (errorHandler != null) {
|
||||
errorHandler.fatalError(saxException);
|
||||
}
|
||||
else {
|
||||
throw saxException;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SAX <code>Locator</code> based on the given StAX <code>Location</code>.
|
||||
*
|
||||
* @param location the location
|
||||
* @see ContentHandler#setDocumentLocator(org.xml.sax.Locator)
|
||||
*/
|
||||
protected void setLocator(Location location) {
|
||||
if (contentHandler != null) {
|
||||
contentHandler.setDocumentLocator(new StaxLocator(location));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template-method that parses the StAX reader passed at construction-time.
|
||||
*/
|
||||
protected abstract void parseInternal() throws SAXException, XMLStreamException;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>Locator</code> interface that is based on a StAX <code>Location</code>.
|
||||
*
|
||||
* @see Locator
|
||||
* @see Location
|
||||
*/
|
||||
private static class StaxLocator implements Locator {
|
||||
|
||||
private Location location;
|
||||
|
||||
protected StaxLocator(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getPublicId() {
|
||||
return location.getPublicId();
|
||||
}
|
||||
|
||||
public String getSystemId() {
|
||||
return location.getSystemId();
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return location.getLineNumber();
|
||||
}
|
||||
|
||||
public int getColumnNumber() {
|
||||
return location.getColumnNumber();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.stream;
|
||||
|
||||
import java.util.Iterator;
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.Location;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.Attribute;
|
||||
import javax.xml.stream.events.Namespace;
|
||||
import javax.xml.stream.events.ProcessingInstruction;
|
||||
import javax.xml.stream.events.StartDocument;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>XMLStreamReader</code> interface that wraps a <code>XMLEventReader</code>. Useful,
|
||||
* because the StAX <code>XMLInputFactory</code> allows one to create a event reader from a stream reader, but not
|
||||
* vice-versa.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class XmlEventStreamReader extends AbstractXmlStreamReader {
|
||||
|
||||
private XMLEvent event;
|
||||
|
||||
private final XMLEventReader eventReader;
|
||||
|
||||
public XmlEventStreamReader(XMLEventReader eventReader) throws XMLStreamException {
|
||||
this.eventReader = eventReader;
|
||||
event = eventReader.nextEvent();
|
||||
}
|
||||
|
||||
public boolean isStandalone() {
|
||||
if (event.isStartDocument()) {
|
||||
return ((StartDocument) event).isStandalone();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
if (event.isStartDocument()) {
|
||||
return ((StartDocument) event).getVersion();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public int getTextStart() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
if (event.isCharacters()) {
|
||||
return event.asCharacters().getData();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public String getPITarget() {
|
||||
if (event.isProcessingInstruction()) {
|
||||
return ((ProcessingInstruction) event).getTarget();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public String getPIData() {
|
||||
if (event.isProcessingInstruction()) {
|
||||
return ((ProcessingInstruction) event).getData();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public int getNamespaceCount() {
|
||||
Iterator namespaces;
|
||||
if (event.isStartElement()) {
|
||||
namespaces = event.asStartElement().getNamespaces();
|
||||
}
|
||||
else if (event.isEndElement()) {
|
||||
namespaces = event.asEndElement().getNamespaces();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return countIterator(namespaces);
|
||||
}
|
||||
|
||||
public NamespaceContext getNamespaceContext() {
|
||||
if (event.isStartElement()) {
|
||||
return event.asStartElement().getNamespaceContext();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public QName getName() {
|
||||
if (event.isStartElement()) {
|
||||
return event.asStartElement().getName();
|
||||
}
|
||||
else if (event.isEndElement()) {
|
||||
return event.asEndElement().getName();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return event.getLocation();
|
||||
}
|
||||
|
||||
public int getEventType() {
|
||||
return event.getEventType();
|
||||
}
|
||||
|
||||
public String getEncoding() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getCharacterEncodingScheme() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getAttributeCount() {
|
||||
if (!event.isStartElement()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
Iterator attributes = event.asStartElement().getAttributes();
|
||||
return countIterator(attributes);
|
||||
}
|
||||
|
||||
public void close() throws XMLStreamException {
|
||||
eventReader.close();
|
||||
}
|
||||
|
||||
public QName getAttributeName(int index) {
|
||||
return getAttribute(index).getName();
|
||||
}
|
||||
|
||||
public String getAttributeType(int index) {
|
||||
return getAttribute(index).getDTDType();
|
||||
}
|
||||
|
||||
public String getAttributeValue(int index) {
|
||||
return getAttribute(index).getValue();
|
||||
}
|
||||
|
||||
public String getNamespacePrefix(int index) {
|
||||
return getNamespace(index).getPrefix();
|
||||
}
|
||||
|
||||
public String getNamespaceURI(int index) {
|
||||
return getNamespace(index).getNamespaceURI();
|
||||
}
|
||||
|
||||
public Object getProperty(String name) throws IllegalArgumentException {
|
||||
return eventReader.getProperty(name);
|
||||
}
|
||||
|
||||
public boolean isAttributeSpecified(int index) {
|
||||
return getAttribute(index).isSpecified();
|
||||
}
|
||||
|
||||
public int next() throws XMLStreamException {
|
||||
event = eventReader.nextEvent();
|
||||
return event.getEventType();
|
||||
}
|
||||
|
||||
public boolean standaloneSet() {
|
||||
if (event.isStartDocument()) {
|
||||
return ((StartDocument) event).standaloneSet();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
private int countIterator(Iterator iterator) {
|
||||
int count = 0;
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next();
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private Attribute getAttribute(int index) {
|
||||
if (!event.isStartElement()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
int count = 0;
|
||||
Iterator attributes = event.asStartElement().getAttributes();
|
||||
while (attributes.hasNext()) {
|
||||
Attribute attribute = (Attribute) attributes.next();
|
||||
if (count == index) {
|
||||
return attribute;
|
||||
}
|
||||
else {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
private Namespace getNamespace(int index) {
|
||||
Iterator namespaces;
|
||||
if (event.isStartElement()) {
|
||||
namespaces = event.asStartElement().getNamespaces();
|
||||
}
|
||||
else if (event.isEndElement()) {
|
||||
namespaces = event.asEndElement().getNamespaces();
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
int count = 0;
|
||||
while (namespaces.hasNext()) {
|
||||
Namespace namespace = (Namespace) namespaces.next();
|
||||
if (count == index) {
|
||||
return namespace;
|
||||
}
|
||||
else {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides classes that help with StAX: the Streaming API for XML. Mostly for internal use by the framework.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.transform;
|
||||
|
||||
import javax.xml.stream.XMLEventFactory;
|
||||
import javax.xml.stream.XMLEventWriter;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import javax.xml.transform.sax.SAXResult;
|
||||
|
||||
import org.springframework.xml.stream.StaxEventContentHandler;
|
||||
import org.springframework.xml.stream.StaxStreamContentHandler;
|
||||
import org.xml.sax.ContentHandler;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>Result</code> tagging interface for StAX writers. Can be constructed with a
|
||||
* <code>XMLEventConsumer</code> or a <code>XMLStreamWriter</code>.
|
||||
* <p/>
|
||||
* This class is necessary because there is no implementation of <code>Source</code> for StaxReaders in JAXP 1.3. There
|
||||
* will be a <code>StaxResult</code> in JAXP 1.4 (JDK 1.6), and by the time that version is available, this class will
|
||||
* probably be deprecated.
|
||||
* <p/>
|
||||
* Even though <code>StaxResult</code> extends from <code>SAXResult</code>, calling the methods of
|
||||
* <code>SAXResult</code> is <strong>not supported</strong>. In general, the only supported operation on this class is
|
||||
* to use the <code>ContentHandler</code> obtained via {@link #getHandler()} to parse an input source using an
|
||||
* <code>XMLReader</code>. Calling {@link #setHandler(org.xml.sax.ContentHandler)} will result in
|
||||
* <code>UnsupportedOperationException</code>s.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see XMLEventWriter
|
||||
* @see XMLStreamWriter
|
||||
* @see javax.xml.transform.Transformer
|
||||
*/
|
||||
public class StaxResult extends SAXResult {
|
||||
|
||||
private XMLEventWriter eventWriter;
|
||||
|
||||
private XMLStreamWriter streamWriter;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>StaxResult</code> with the specified <code>XMLStreamWriter</code>.
|
||||
*
|
||||
* @param streamWriter the <code>XMLStreamWriter</code> to write to
|
||||
*/
|
||||
public StaxResult(XMLStreamWriter streamWriter) {
|
||||
super.setHandler(new StaxStreamContentHandler(streamWriter));
|
||||
this.streamWriter = streamWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>StaxResult</code> with the specified <code>XMLEventWriter</code>.
|
||||
*
|
||||
* @param eventWriter the <code>XMLEventWriter</code> to write to
|
||||
*/
|
||||
public StaxResult(XMLEventWriter eventWriter) {
|
||||
super.setHandler(new StaxEventContentHandler(eventWriter));
|
||||
this.eventWriter = eventWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>StaxResult</code> with the specified <code>XMLEventWriter</code> and
|
||||
* <code>XMLEventFactory</code>.
|
||||
*
|
||||
* @param eventWriter the <code>XMLEventWriter</code> to write to
|
||||
* @param eventFactory the <code>XMLEventFactory</code> to use for creating events
|
||||
*/
|
||||
public StaxResult(XMLEventWriter eventWriter, XMLEventFactory eventFactory) {
|
||||
super.setHandler(new StaxEventContentHandler(eventWriter, eventFactory));
|
||||
this.eventWriter = eventWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>XMLEventWriter</code> used by this <code>StaxResult</code>. If this <code>StaxResult</code> was
|
||||
* created with an <code>XMLStreamWriter</code>, the result will be <code>null</code>.
|
||||
*
|
||||
* @return the StAX event writer used by this result
|
||||
* @see #StaxResult(javax.xml.stream.XMLEventWriter)
|
||||
*/
|
||||
public XMLEventWriter getXMLEventWriter() {
|
||||
return eventWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>XMLStreamWriter</code> used by this <code>StaxResult</code>. If this <code>StaxResult</code>
|
||||
* was created with an <code>XMLEventConsumer</code>, the result will be <code>null</code>.
|
||||
*
|
||||
* @return the StAX stream writer used by this result
|
||||
* @see #StaxResult(javax.xml.stream.XMLStreamWriter)
|
||||
*/
|
||||
public XMLStreamWriter getXMLStreamWriter() {
|
||||
return streamWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a <code>UnsupportedOperationException</code>.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public void setHandler(ContentHandler handler) {
|
||||
throw new UnsupportedOperationException("setHandler is not supported");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.transform;
|
||||
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
|
||||
import org.springframework.xml.stream.StaxEventXmlReader;
|
||||
import org.springframework.xml.stream.StaxStreamXmlReader;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>Source</code> tagging interface for StAX readers. Can be constructed with a
|
||||
* <code>XMLEventReader</code> or a <code>XMLStreamReader</code>.
|
||||
* <p/>
|
||||
* This class is necessary because there is no implementation of <code>Source</code> for StaxReaders in JAXP 1.3. There
|
||||
* will be a <code>StaxSource</code> in JAXP 1.4 (JDK 1.6), and by the time that version is available, this class will
|
||||
* probably be deprecated.
|
||||
* <p/>
|
||||
* Even though <code>StaxSource</code> extends from <code>SAXSource</code>, calling the methods of
|
||||
* <code>SAXSource</code> is <strong>not supported</strong>. In general, the only supported operation on this class is
|
||||
* to use the <code>XMLReader</code> obtained via {@link #getXMLReader()} to parse the input source obtained via {@link
|
||||
* #getInputSource()}. Calling {@link #setXMLReader(org.xml.sax.XMLReader)} or {@link
|
||||
* #setInputSource(org.xml.sax.InputSource)} will result in <code>UnsupportedOperationException</code>s.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see XMLEventReader
|
||||
* @see XMLStreamReader
|
||||
* @see javax.xml.transform.Transformer
|
||||
*/
|
||||
public class StaxSource extends SAXSource {
|
||||
|
||||
private XMLEventReader eventReader;
|
||||
|
||||
private XMLStreamReader streamReader;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>StaxSource</code> with the specified <code>XMLStreamReader</code>. The
|
||||
* supplied stream reader must be in <code>XMLStreamConstants.START_DOCUMENT</code> or
|
||||
* <code>XMLStreamConstants.START_ELEMENT</code> state.
|
||||
*
|
||||
* @param streamReader the <code>XMLStreamReader</code> to read from
|
||||
* @throws IllegalStateException if the reader is not at the start of a document or element
|
||||
*/
|
||||
public StaxSource(XMLStreamReader streamReader) {
|
||||
super(new StaxStreamXmlReader(streamReader), new InputSource());
|
||||
this.streamReader = streamReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>StaxSource</code> with the specified <code>XMLEventReader</code>. The
|
||||
* supplied event reader must be in <code>XMLStreamConstants.START_DOCUMENT</code> or
|
||||
* <code>XMLStreamConstants.START_ELEMENT</code> state.
|
||||
*
|
||||
* @param eventReader the <code>XMLEventReader</code> to read from
|
||||
* @throws IllegalStateException if the reader is not at the start of a document or element
|
||||
*/
|
||||
public StaxSource(XMLEventReader eventReader) {
|
||||
super(new StaxEventXmlReader(eventReader), new InputSource());
|
||||
this.eventReader = eventReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>XMLEventReader</code> used by this <code>StaxSource</code>. If this <code>StaxSource</code> was
|
||||
* created with an <code>XMLStreamReader</code>, the result will be <code>null</code>.
|
||||
*
|
||||
* @return the StAX event reader used by this source
|
||||
* @see StaxSource#StaxSource(javax.xml.stream.XMLEventReader)
|
||||
*/
|
||||
public XMLEventReader getXMLEventReader() {
|
||||
return eventReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>XMLStreamReader</code> used by this <code>StaxSource</code>. If this <code>StaxSource</code>
|
||||
* was created with an <code>XMLEventReader</code>, the result will be <code>null</code>.
|
||||
*
|
||||
* @return the StAX event reader used by this source
|
||||
* @see StaxSource#StaxSource(javax.xml.stream.XMLEventReader)
|
||||
*/
|
||||
public XMLStreamReader getXMLStreamReader() {
|
||||
return streamReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a <code>UnsupportedOperationException</code>.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public void setInputSource(InputSource inputSource) {
|
||||
throw new UnsupportedOperationException("setInputSource is not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a <code>UnsupportedOperationException</code>.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public void setXMLReader(XMLReader reader) {
|
||||
throw new UnsupportedOperationException("setXMLReader is not supported");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.transform;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
/**
|
||||
* Convenient subclass of <code>StreamResult</code> that writes to a <code>StringWriter</code>. The resulting string can
|
||||
* be retrieved via <code>toString()</code>.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #toString()
|
||||
*/
|
||||
public class StringResult extends StreamResult {
|
||||
|
||||
public StringResult() {
|
||||
super(new StringWriter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the written XML as a string.
|
||||
*/
|
||||
public String toString() {
|
||||
return getWriter().toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.transform;
|
||||
|
||||
import java.io.StringReader;
|
||||
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
/**
|
||||
* Convenient subclass of <code>StreamSource</code> that reads from a <code>StringReader</code>. The string to be read
|
||||
* can be set via the constructor.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class StringSource extends StreamSource {
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the <code>StringSource</code> with the given string content.
|
||||
*
|
||||
* @param content the content
|
||||
*/
|
||||
public StringSource(String content) {
|
||||
super(new StringReader(content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the <code>StringSource</code> with the given string content and system id.
|
||||
*
|
||||
* @param content the content
|
||||
* @param systemId a string that conforms to the URI syntax
|
||||
*/
|
||||
public StringSource(String content, String systemId) {
|
||||
super(new StringReader(content), systemId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides classes that help with XML transformations. Mostly for internal use by the framework.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.validation;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* Internal class that uses JAXP 1.0 features to create <code>XmlValidator</code> instances.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
abstract class Jaxp10ValidatorFactory {
|
||||
|
||||
private static final String SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
|
||||
|
||||
private static final String SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
|
||||
|
||||
static XmlValidator createValidator(Resource[] schemaResources, String schemaLanguage) throws IOException {
|
||||
InputSource[] inputSources = new InputSource[schemaResources.length];
|
||||
for (int i = 0; i < schemaResources.length; i++) {
|
||||
inputSources[i] = new InputSource(schemaResources[i].getInputStream());
|
||||
inputSources[i].setSystemId(SchemaLoaderUtils.getSystemId(schemaResources[i]));
|
||||
}
|
||||
return new Jaxp10Validator(inputSources, schemaLanguage);
|
||||
}
|
||||
|
||||
private static class Jaxp10Validator implements XmlValidator {
|
||||
|
||||
private SAXParserFactory parserFactory;
|
||||
|
||||
private TransformerFactory transformerFactory;
|
||||
|
||||
private InputSource[] schemaInputSources;
|
||||
|
||||
private String schemaLanguage;
|
||||
|
||||
private Jaxp10Validator(InputSource[] schemaInputSources, String schemaLanguage) {
|
||||
this.schemaInputSources = schemaInputSources;
|
||||
this.schemaLanguage = schemaLanguage;
|
||||
transformerFactory = TransformerFactory.newInstance();
|
||||
parserFactory = SAXParserFactory.newInstance();
|
||||
parserFactory.setNamespaceAware(true);
|
||||
parserFactory.setValidating(true);
|
||||
}
|
||||
|
||||
public SAXParseException[] validate(Source source) throws IOException {
|
||||
SAXParser parser = createSAXParser();
|
||||
ValidationErrorHandler errorHandler = new ValidationErrorHandler();
|
||||
try {
|
||||
if (source instanceof SAXSource) {
|
||||
validateSAXSource((SAXSource) source, parser, errorHandler);
|
||||
}
|
||||
else if (source instanceof StreamSource) {
|
||||
validateStreamSource((StreamSource) source, parser, errorHandler);
|
||||
}
|
||||
else if (source instanceof DOMSource) {
|
||||
validateDOMSource((DOMSource) source, parser, errorHandler);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Source [" + source.getClass().getName() +
|
||||
"] is neither SAXSource, DOMSource, nor StreamSource");
|
||||
}
|
||||
return errorHandler.getErrors();
|
||||
}
|
||||
catch (SAXException ex) {
|
||||
throw new XmlValidationException("Could not validate source: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateDOMSource(DOMSource domSource, SAXParser parser, ValidationErrorHandler errorHandler)
|
||||
throws IOException, SAXException {
|
||||
try {
|
||||
// Sadly, JAXP 1.0 DOM doesn't implement DOM level 3, so we cannot use Document.normalizeDocument()
|
||||
// Instead, we write the Document to a Stream, and validate that
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
transformer.transform(domSource, new StreamResult(outputStream));
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
validateStreamSource(new StreamSource(inputStream), parser, errorHandler);
|
||||
}
|
||||
catch (TransformerException ex) {
|
||||
throw new XmlValidationException("Could not validate DOM source: " + ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void validateStreamSource(StreamSource streamSource,
|
||||
SAXParser parser,
|
||||
ValidationErrorHandler errorHandler) throws SAXException, IOException {
|
||||
if (streamSource.getInputStream() != null) {
|
||||
parser.parse(streamSource.getInputStream(), errorHandler);
|
||||
}
|
||||
else if (streamSource.getReader() != null) {
|
||||
parser.parse(new InputSource(streamSource.getReader()), errorHandler);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("StreamSource contains neither InputStream nor Reader");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateSAXSource(SAXSource source, SAXParser parser, ValidationErrorHandler errorHandler)
|
||||
throws SAXException, IOException {
|
||||
parser.parse(source.getInputSource(), errorHandler);
|
||||
}
|
||||
|
||||
private SAXParser createSAXParser() {
|
||||
try {
|
||||
SAXParser parser = parserFactory.newSAXParser();
|
||||
parser.setProperty(SCHEMA_LANGUAGE, schemaLanguage);
|
||||
parser.setProperty(SCHEMA_SOURCE, schemaInputSources);
|
||||
return parser;
|
||||
}
|
||||
catch (ParserConfigurationException ex) {
|
||||
throw new XmlValidationException("Could not create SAXParser: " + ex.getMessage(), ex);
|
||||
}
|
||||
catch (SAXException ex) {
|
||||
throw new XmlValidationException("Could not create SAXParser: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>DefaultHandler</code> extension that stores errors and fatal errors in a list.
|
||||
*/
|
||||
private static class ValidationErrorHandler extends DefaultHandler {
|
||||
|
||||
private List errors = new ArrayList();
|
||||
|
||||
private SAXParseException[] getErrors() {
|
||||
return (SAXParseException[]) errors.toArray(new SAXParseException[errors.size()]);
|
||||
}
|
||||
|
||||
public void warning(SAXParseException ex) throws SAXException {
|
||||
}
|
||||
|
||||
public void error(SAXParseException ex) throws SAXException {
|
||||
errors.add(ex);
|
||||
}
|
||||
|
||||
public void fatalError(SAXParseException ex) throws SAXException {
|
||||
errors.add(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.validation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.validation.Schema;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
/**
|
||||
* Internal class that uses JAXP 1.0 features to create <code>XmlValidator</code> instances.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
abstract class Jaxp13ValidatorFactory {
|
||||
|
||||
static XmlValidator createValidator(Resource[] resources, String schemaLanguage) throws IOException {
|
||||
try {
|
||||
Schema schema = SchemaLoaderUtils.loadSchema(resources, schemaLanguage);
|
||||
return new Jaxp13Validator(schema);
|
||||
}
|
||||
catch (SAXException ex) {
|
||||
throw new XmlValidationException("Could not create Schema: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Jaxp13Validator implements XmlValidator {
|
||||
|
||||
private Schema schema;
|
||||
|
||||
public Jaxp13Validator(Schema schema) {
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public SAXParseException[] validate(Source source) throws IOException {
|
||||
javax.xml.validation.Validator validator = schema.newValidator();
|
||||
ValidationErrorHandler errorHandler = new ValidationErrorHandler();
|
||||
validator.setErrorHandler(errorHandler);
|
||||
try {
|
||||
validator.validate(source);
|
||||
return errorHandler.getErrors();
|
||||
}
|
||||
catch (SAXException ex) {
|
||||
throw new XmlValidationException("Could not validate source: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>ErrorHandler</code> implementation that stores errors and fatal errors in a list.
|
||||
*/
|
||||
private static class ValidationErrorHandler implements ErrorHandler {
|
||||
|
||||
private List errors = new ArrayList();
|
||||
|
||||
private SAXParseException[] getErrors() {
|
||||
return (SAXParseException[]) errors.toArray(new SAXParseException[errors.size()]);
|
||||
}
|
||||
|
||||
public void warning(SAXParseException ex) throws SAXException {
|
||||
}
|
||||
|
||||
public void error(SAXParseException ex) throws SAXException {
|
||||
errors.add(ex);
|
||||
}
|
||||
|
||||
public void fatalError(SAXParseException ex) throws SAXException {
|
||||
errors.add(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.validation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Convenient utility methods for loading of <code>javax.xml.validation.Schema</code> objects, performing standard
|
||||
* handling of input streams.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public abstract class SchemaLoaderUtils {
|
||||
|
||||
/**
|
||||
* Load schema from the given resource.
|
||||
*
|
||||
* @param resource the resource to load from
|
||||
* @param schemaLanguage the language of the schema. Can be <code>XMLConstants.W3C_XML_SCHEMA_NS_URI</code> or
|
||||
* <code>XMLConstants.RELAXNG_NS_URI</code>.
|
||||
* @throws IOException if loading failed
|
||||
* @throws SAXException if loading failed
|
||||
* @see javax.xml.XMLConstants#W3C_XML_SCHEMA_NS_URI
|
||||
* @see javax.xml.XMLConstants#RELAXNG_NS_URI
|
||||
*/
|
||||
public static Schema loadSchema(Resource resource, String schemaLanguage) throws IOException, SAXException {
|
||||
return loadSchema(new Resource[]{resource}, schemaLanguage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load schema from the given resource.
|
||||
*
|
||||
* @param resources the resources to load from
|
||||
* @param schemaLanguage the language of the schema. Can be <code>XMLConstants.W3C_XML_SCHEMA_NS_URI</code> or
|
||||
* <code>XMLConstants.RELAXNG_NS_URI</code>.
|
||||
* @throws IOException if loading failed
|
||||
* @throws SAXException if loading failed
|
||||
* @see javax.xml.XMLConstants#W3C_XML_SCHEMA_NS_URI
|
||||
* @see javax.xml.XMLConstants#RELAXNG_NS_URI
|
||||
*/
|
||||
public static Schema loadSchema(Resource[] resources, String schemaLanguage) throws IOException, SAXException {
|
||||
Assert.notEmpty(resources, "No resources given");
|
||||
Assert.hasLength(schemaLanguage, "No schema language provided");
|
||||
StreamSource[] schemaSources = new StreamSource[resources.length];
|
||||
try {
|
||||
for (int i = 0; i < resources.length; i++) {
|
||||
Assert.notNull(resources[i], "Resource is null");
|
||||
Assert.isTrue(resources[i].exists(), "Resource " + resources[i] + " does not exist");
|
||||
schemaSources[i] = new StreamSource(resources[i].getInputStream(), getSystemId(resources[i]));
|
||||
}
|
||||
SchemaFactory schemaFactory = SchemaFactory.newInstance(schemaLanguage);
|
||||
return schemaFactory.newSchema(schemaSources);
|
||||
}
|
||||
finally {
|
||||
for (int i = 0; i < schemaSources.length; i++) {
|
||||
if (schemaSources[i] != null) {
|
||||
InputStream inputStream = schemaSources[i].getInputStream();
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the URL from the given resource as System ID. Returns <code>null</code> if it cannot be openened.
|
||||
*/
|
||||
public static String getSystemId(Resource resource) {
|
||||
try {
|
||||
return resource.getURL().toString();
|
||||
}
|
||||
catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.validation;
|
||||
|
||||
import org.springframework.xml.XmlException;
|
||||
|
||||
/**
|
||||
* Expection thrown when a validation error occurs
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class XmlValidationException extends XmlException {
|
||||
|
||||
public XmlValidationException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public XmlValidationException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.validation;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.xml.transform.Source;
|
||||
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
/**
|
||||
* Simple processor that validates a given <code>Source</code>. Can be created via the
|
||||
* <code>XmlValidatorFactory</code>.
|
||||
* <p/>
|
||||
* <code>XmlValidator</code> instances are designed to be thread safe.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see XmlValidatorFactory#createValidator(org.springframework.core.io.Resource, String)
|
||||
*/
|
||||
public interface XmlValidator {
|
||||
|
||||
/**
|
||||
* Validates the given <code>Source</code>, and returns an array of <code>SAXParseException</code>s as result. The
|
||||
* array will be empty if no validation errors are found.
|
||||
*
|
||||
* @param source the input document
|
||||
* @return an array of <code>SAXParseException</code>s
|
||||
* @throws IOException if the <code>source</code> cannot be read
|
||||
* @throws XmlValidationException if the <code>source</code> cannot be validated
|
||||
*/
|
||||
SAXParseException[] validate(Source source) throws IOException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.validation;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.xml.JaxpVersion;
|
||||
|
||||
/**
|
||||
* Factory for <code>XmlValidator</code>s, being aware of JAXP 1.3 <code>XmlValidator</code>s, and JAXP 1.0 parsing
|
||||
* capababilities. Mainly for internal use within the framework.
|
||||
* <p/>
|
||||
* The goal of this class is to avoid runtime dependencies on JAXP 1.3 by using the best validation implementation that
|
||||
* is available. Prefers JAXP 1.3 <code>XmlValidator</code> implementations to a custom, SAX-based implementation.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see XmlValidator
|
||||
*/
|
||||
public abstract class XmlValidatorFactory {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(XmlValidatorFactory.class);
|
||||
|
||||
/**
|
||||
* Constant that defines a W3C XML Schema.
|
||||
*/
|
||||
public static final String SCHEMA_W3C_XML = "http://www.w3.org/2001/XMLSchema";
|
||||
|
||||
/**
|
||||
* Constant that defines a RELAX NG Schema.
|
||||
*/
|
||||
public static final String SCHEMA_RELAX_NG = "http://relaxng.org/ns/structure/1.0";
|
||||
|
||||
/**
|
||||
* Create a <code>XmlValidator</code> with the given schema resource and schema language type. The schema language
|
||||
* must be one of the <code>SCHEMA_XXX</code> constants.
|
||||
*
|
||||
* @param schemaResource a resource that locates the schema to validate against
|
||||
* @param schemaLanguage the language of the schema
|
||||
* @return a validator
|
||||
* @throws IOException if the schema resource cannot be read
|
||||
* @throws IllegalArgumentException if the schema language is not supported
|
||||
* @throws IllegalStateException if JAXP 1.0 cannot be located
|
||||
* @throws XmlValidationException if a <code>XmlValidator</code> cannot be created
|
||||
* @see #SCHEMA_RELAX_NG
|
||||
* @see #SCHEMA_W3C_XML
|
||||
*/
|
||||
public static XmlValidator createValidator(Resource schemaResource, String schemaLanguage) throws IOException {
|
||||
return createValidator(new Resource[]{schemaResource}, schemaLanguage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a <code>XmlValidator</code> with the given schema resources and schema language type. The schema language
|
||||
* must be one of the <code>SCHEMA_XXX</code> constants.
|
||||
*
|
||||
* @param schemaResources an array of resource that locate the schemas to validate against
|
||||
* @param schemaLanguage the language of the schemas
|
||||
* @return a validator
|
||||
* @throws IOException if the schema resource cannot be read
|
||||
* @throws IllegalArgumentException if the schema language is not supported
|
||||
* @throws IllegalStateException if JAXP 1.0 cannot be located
|
||||
* @throws XmlValidationException if a <code>XmlValidator</code> cannot be created
|
||||
* @see #SCHEMA_RELAX_NG
|
||||
* @see #SCHEMA_W3C_XML
|
||||
*/
|
||||
public static XmlValidator createValidator(Resource[] schemaResources, String schemaLanguage) throws IOException {
|
||||
Assert.notEmpty(schemaResources, "No resources given");
|
||||
Assert.hasLength(schemaLanguage, "No schema language provided");
|
||||
Assert.isTrue(SCHEMA_W3C_XML.equals(schemaLanguage) || SCHEMA_RELAX_NG.equals(schemaLanguage),
|
||||
"Invalid schema language: " + schemaLanguage);
|
||||
for (int i = 0; i < schemaResources.length; i++) {
|
||||
Assert.isTrue(schemaResources[i].exists(), "schema [" + schemaResources + "] does not exist");
|
||||
}
|
||||
if (JaxpVersion.getJaxpVersion() >= JaxpVersion.JAXP_13) {
|
||||
logger.debug("Creating JAXP 1.3 XmlValidator");
|
||||
return Jaxp13ValidatorFactory.createValidator(schemaResources, schemaLanguage);
|
||||
}
|
||||
else if (JaxpVersion.getJaxpVersion() >= JaxpVersion.JAXP_10) {
|
||||
logger.debug("Creating JAXP 1.0 XmlValidator");
|
||||
return Jaxp10ValidatorFactory.createValidator(schemaResources, schemaLanguage);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Could not locate JAXP 1.0 or higher.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides classes for XML validation in JAXP 1.0 and JAXP 1.3. Mostly for internal use by the framework.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.xpath;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jaxen.JaxenException;
|
||||
import org.jaxen.SimpleNamespaceContext;
|
||||
import org.jaxen.XPath;
|
||||
import org.jaxen.dom.DOMXPath;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Jaxen-specific factory for creating <code>XPathExpression</code>s.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #createXPathExpression(String)
|
||||
*/
|
||||
abstract class JaxenXPathExpressionFactory {
|
||||
|
||||
/**
|
||||
* Creates a Jaxen <code>XPathExpression</code> from the given string expression.
|
||||
*
|
||||
* @param expression the XPath expression
|
||||
* @return the compiled <code>XPathExpression</code>
|
||||
* @throws XPathParseException when the given expression cannot be parsed
|
||||
*/
|
||||
static XPathExpression createXPathExpression(String expression) {
|
||||
try {
|
||||
XPath xpath = new DOMXPath(expression);
|
||||
return new JaxenXpathExpression(xpath);
|
||||
}
|
||||
catch (JaxenException ex) {
|
||||
throw new org.springframework.xml.xpath.XPathParseException(
|
||||
"Could not compile [" + expression + "] to a XPathExpression: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Jaxen <code>XPathExpression</code> from the given string expression and prefixes.
|
||||
*
|
||||
* @param expression the XPath expression
|
||||
* @param namespaces the namespaces
|
||||
* @return the compiled <code>XPathExpression</code>
|
||||
* @throws XPathParseException when the given expression cannot be parsed
|
||||
*/
|
||||
public static XPathExpression createXPathExpression(String expression, Map namespaces) {
|
||||
try {
|
||||
XPath xpath = new DOMXPath(expression);
|
||||
xpath.setNamespaceContext(new SimpleNamespaceContext(namespaces));
|
||||
return new JaxenXpathExpression(xpath);
|
||||
}
|
||||
catch (JaxenException ex) {
|
||||
throw new org.springframework.xml.xpath.XPathParseException(
|
||||
"Could not compile [" + expression + "] to a XPathExpression: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Jaxen implementation of the <code>XPathExpression</code> interface.
|
||||
*/
|
||||
private static class JaxenXpathExpression implements XPathExpression {
|
||||
|
||||
private XPath xpath;
|
||||
|
||||
private JaxenXpathExpression(XPath xpath) {
|
||||
this.xpath = xpath;
|
||||
}
|
||||
|
||||
public Node evaluateAsNode(Node node) {
|
||||
try {
|
||||
return (Node) xpath.selectSingleNode(node);
|
||||
}
|
||||
catch (JaxenException ex) {
|
||||
throw new XPathException("Could not evaluate XPath expression [" + xpath + "] :" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean evaluateAsBoolean(Node node) {
|
||||
try {
|
||||
return xpath.booleanValueOf(node);
|
||||
}
|
||||
catch (JaxenException ex) {
|
||||
throw new XPathException("Could not evaluate XPath expression [" + xpath + "] :" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public double evaluateAsNumber(Node node) {
|
||||
try {
|
||||
return xpath.numberValueOf(node).doubleValue();
|
||||
}
|
||||
catch (JaxenException ex) {
|
||||
throw new XPathException("Could not evaluate XPath expression [" + xpath + "] :" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String evaluateAsString(Node node) {
|
||||
try {
|
||||
return xpath.stringValueOf(node);
|
||||
}
|
||||
catch (JaxenException ex) {
|
||||
throw new XPathException("Could not evaluate XPath expression [" + xpath + "] :" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public Node[] evaluateAsNodes(Node node) {
|
||||
try {
|
||||
List result = xpath.selectNodes(node);
|
||||
return (Node[]) result.toArray(new Node[result.size()]);
|
||||
}
|
||||
catch (JaxenException ex) {
|
||||
throw new XPathException("Could not evaluate XPath expression [" + xpath + "] :" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.xpath;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import org.springframework.xml.namespace.SimpleNamespaceContext;
|
||||
|
||||
/**
|
||||
* JAXP 1.3-specific factory creating <code>XPathExpression</code>s.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #createXPathExpression(String)
|
||||
*/
|
||||
abstract class Jaxp13XPathExpressionFactory {
|
||||
|
||||
private static XPathFactory xpathFactory;
|
||||
|
||||
static {
|
||||
xpathFactory = XPathFactory.newInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JAXP 1.3 <code>XPathExpression</code> from the given string expression.
|
||||
*
|
||||
* @param expression the XPath expression
|
||||
* @return the compiled <code>XPathExpression</code>
|
||||
* @throws XPathParseException when the given expression cannot be parsed
|
||||
*/
|
||||
static XPathExpression createXPathExpression(String expression) {
|
||||
try {
|
||||
XPath xpath = xpathFactory.newXPath();
|
||||
javax.xml.xpath.XPathExpression xpathExpression = xpath.compile(expression);
|
||||
return new Jaxp13XPathExpression(xpathExpression);
|
||||
}
|
||||
catch (XPathExpressionException ex) {
|
||||
throw new org.springframework.xml.xpath.XPathParseException(
|
||||
"Could not compile [" + expression + "] to a XPathExpression: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JAXP 1.3 <code>XPathExpression</code> from the given string expression and namespaces.
|
||||
*
|
||||
* @param expression the XPath expression
|
||||
* @param namespaces the namespaces
|
||||
* @return the compiled <code>XPathExpression</code>
|
||||
* @throws XPathParseException when the given expression cannot be parsed
|
||||
*/
|
||||
public static XPathExpression createXPathExpression(String expression, Map namespaces) {
|
||||
try {
|
||||
XPath xpath = xpathFactory.newXPath();
|
||||
SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
|
||||
namespaceContext.setBindings(namespaces);
|
||||
xpath.setNamespaceContext(namespaceContext);
|
||||
javax.xml.xpath.XPathExpression xpathExpression = xpath.compile(expression);
|
||||
return new Jaxp13XPathExpression(xpathExpression);
|
||||
}
|
||||
catch (XPathExpressionException ex) {
|
||||
throw new org.springframework.xml.xpath.XPathParseException(
|
||||
"Could not compile [" + expression + "] to a XPathExpression: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JAXP 1.3 implementation of the <code>XPathExpression</code> interface.
|
||||
*/
|
||||
private static class Jaxp13XPathExpression implements XPathExpression {
|
||||
|
||||
javax.xml.xpath.XPathExpression xpathExpression;
|
||||
|
||||
private Jaxp13XPathExpression(javax.xml.xpath.XPathExpression xpathExpression) {
|
||||
this.xpathExpression = xpathExpression;
|
||||
}
|
||||
|
||||
public String evaluateAsString(Node node) {
|
||||
return (String) evaluate(node, XPathConstants.STRING);
|
||||
}
|
||||
|
||||
public Node[] evaluateAsNodes(Node node) {
|
||||
NodeList nodeList = (NodeList) evaluate(node, XPathConstants.NODESET);
|
||||
return toNodeArray(nodeList);
|
||||
}
|
||||
|
||||
private Object evaluate(Node node, QName returnType) {
|
||||
try {
|
||||
return xpathExpression.evaluate(node, returnType);
|
||||
}
|
||||
catch (XPathExpressionException ex) {
|
||||
throw new XPathException("Could not evaluate XPath expression:" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Node[] toNodeArray(NodeList nodeList) {
|
||||
Node[] result = new Node[nodeList.getLength()];
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
result[i] = nodeList.item(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public double evaluateAsNumber(Node node) {
|
||||
Double result = (Double) evaluate(node, XPathConstants.NUMBER);
|
||||
return result.doubleValue();
|
||||
}
|
||||
|
||||
public boolean evaluateAsBoolean(Node node) {
|
||||
Boolean result = (Boolean) evaluate(node, XPathConstants.BOOLEAN);
|
||||
return result.booleanValue();
|
||||
}
|
||||
|
||||
public Node evaluateAsNode(Node node) {
|
||||
return (Node) evaluate(node, XPathConstants.NODE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.xpath;
|
||||
|
||||
import org.springframework.xml.XmlException;
|
||||
|
||||
/**
|
||||
* Exception thrown when an error occurs during XPath processing.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class XPathException extends XmlException {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>XPathException</code> with the specific detail message.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
public XPathException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>XPathException</code> with the specific detail message and exception.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param throwable the wrapped exception
|
||||
*/
|
||||
public XPathException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.xpath;
|
||||
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Defines the contract for a precompiled XPath expression. Concrete instances can be obtained through the
|
||||
* <code>XPathExpressionFactory</code>.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see XPathExpressionFactory
|
||||
*/
|
||||
public interface XPathExpression {
|
||||
|
||||
/**
|
||||
* Evaluates the given expression as a <code>Node</code>. Returns the evaluation of the expression, or
|
||||
* <code>null</code> if it is invalid.
|
||||
*
|
||||
* @param node the starting point
|
||||
* @return the result of the evaluation
|
||||
*/
|
||||
Node evaluateAsNode(Node node);
|
||||
|
||||
/**
|
||||
* Evaluates the given expression as a <code>boolean</code>. Returns the boolean evaluation of the expression, or
|
||||
* <code>false</code> if it is invalid.
|
||||
*
|
||||
* @param node the starting point
|
||||
* @return the result of the evaluation
|
||||
*/
|
||||
boolean evaluateAsBoolean(Node node);
|
||||
|
||||
/**
|
||||
* Evaluates the given expression as a number (<code>double</code>). Returns the numeric evaluation of the
|
||||
* expression, or <code>Double.NaN</code> if it is invalid.
|
||||
*
|
||||
* @param node the starting point
|
||||
* @return the result of the evaluation
|
||||
* @see Double#NaN
|
||||
*/
|
||||
double evaluateAsNumber(Node node);
|
||||
|
||||
/**
|
||||
* Evaluates the given expression, and returns the first <code>Node</code> that conforms to it. Returns
|
||||
* <code>null</code> if no result could be found.
|
||||
*
|
||||
* @param node the starting point
|
||||
* @return the first <code>Node</code> that is selected by the expression
|
||||
*/
|
||||
String evaluateAsString(Node node);
|
||||
|
||||
/**
|
||||
* Evaluates the given expression, and returns all <code>Node</code>s that conform to it. Returns and empty array if
|
||||
* no result could be found.
|
||||
*
|
||||
* @param node the starting point
|
||||
* @return the <code>Node</code>s that are selected by the expression
|
||||
*/
|
||||
Node[] evaluateAsNodes(Node node);
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.xpath;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.xml.JaxpVersion;
|
||||
|
||||
/**
|
||||
* Factory for compiled <code>XPathExpression</code>s, being aware of JAXP 1.3+ XPath functionality, Jaxen, and Xalan.
|
||||
* Mainly for internal use of the framework.
|
||||
* <p/>
|
||||
* The goal of this class is to avoid runtime dependencies a specific XPath engine, simply using the best XPath
|
||||
* implementation that is available. Prefers JAXP 1.3+ XPath implementations to Jaxen, and falls back to Xalan.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see XPathExpression
|
||||
*/
|
||||
public abstract class XPathExpressionFactory {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(XPathExpressionFactory.class);
|
||||
|
||||
private static final String XALAN_XPATH_CLASS_NAME = "org.apache.xpath.XPath";
|
||||
|
||||
private static boolean xalanXPathAvailable;
|
||||
|
||||
private static final String JAXEN_CLASS_NAME = "org.jaxen.XPath";
|
||||
|
||||
private static boolean jaxenAvailable;
|
||||
|
||||
static {
|
||||
// Check whether JAXP 1.3, Resin, Jaxen, or Xalan are available
|
||||
if (JaxpVersion.getJaxpVersion() >= JaxpVersion.JAXP_13) {
|
||||
logger.info("JAXP 1.3 available");
|
||||
}
|
||||
try {
|
||||
Class.forName(JAXEN_CLASS_NAME);
|
||||
jaxenAvailable = true;
|
||||
logger.info("Jaxen available");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
jaxenAvailable = false;
|
||||
}
|
||||
try {
|
||||
Class.forName(XALAN_XPATH_CLASS_NAME);
|
||||
xalanXPathAvailable = true;
|
||||
logger.info("Xalan available");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
xalanXPathAvailable = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a compiled XPath expression using the given string.
|
||||
*
|
||||
* @param expression the XPath expression
|
||||
* @return the compiled XPath expression
|
||||
* @throws IllegalStateException if neither JAXP 1.3+, Jaxen, or Xalan are available
|
||||
* @throws XPathParseException if the given expression cannot be parsed
|
||||
*/
|
||||
public static XPathExpression createXPathExpression(String expression)
|
||||
throws IllegalStateException, XPathParseException {
|
||||
return createXPathExpression(expression, Collections.EMPTY_MAP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a compiled XPath expression using the given string and namespaces. The namespace map should consist of
|
||||
* string prefixes mapped to string namespaces.
|
||||
*
|
||||
* @param expression the XPath expression
|
||||
* @param namespaces a map that binds string prefixes to string namespaces
|
||||
* @return the compiled XPath expression
|
||||
* @throws IllegalStateException if neither JAXP 1.3+, Jaxen, or Xalan are available
|
||||
* @throws XPathParseException if the given expression cannot be parsed
|
||||
*/
|
||||
public static XPathExpression createXPathExpression(String expression, Map namespaces)
|
||||
throws IllegalStateException, XPathParseException {
|
||||
Assert.hasLength(expression, "expression is empty");
|
||||
if (JaxpVersion.getJaxpVersion() >= JaxpVersion.JAXP_13) {
|
||||
logger.debug("Creating [javax.xml.xpath.XPathExpression]");
|
||||
return Jaxp13XPathExpressionFactory.createXPathExpression(expression, namespaces);
|
||||
}
|
||||
else if (jaxenAvailable) {
|
||||
logger.debug("Creating [org.jaxen.XPath]");
|
||||
return JaxenXPathExpressionFactory.createXPathExpression(expression, namespaces);
|
||||
}
|
||||
else if (xalanXPathAvailable) {
|
||||
logger.debug("Creating [org.apache.xpath.XPath]");
|
||||
return XalanXPathExpressionFactory.createXPathExpression(expression, namespaces);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"Could not create XPathExpression: could not locate JAXP 1.3, Resin, Xalan on the class path");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.xpath;
|
||||
|
||||
/**
|
||||
* Exception throws when a XPath expression cannot be parsed.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class XPathParseException extends XPathException {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>XPathParseException</code> with the specific detail message.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
public XPathParseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the <code>XPathParseException</code> with the specific detail message and
|
||||
* exception.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param throwable the wrapped exception
|
||||
*/
|
||||
public XPathParseException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.xml.xpath;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.transform.TransformerException;
|
||||
|
||||
import org.apache.xml.utils.PrefixResolver;
|
||||
import org.apache.xpath.XPath;
|
||||
import org.apache.xpath.XPathContext;
|
||||
import org.apache.xpath.objects.XObject;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.traversal.NodeIterator;
|
||||
|
||||
/**
|
||||
* Xalan-specific factory creating <code>XPathExpression</code>s.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #createXPathExpression(String)
|
||||
*/
|
||||
abstract class XalanXPathExpressionFactory {
|
||||
|
||||
/**
|
||||
* Creates a Xalan <code>XPathExpression</code> from the given string expression.
|
||||
*
|
||||
* @param expression the XPath expression
|
||||
* @return the compiled <code>XPathExpression</code>
|
||||
* @throws XPathParseException when the given expression cannot be parsed
|
||||
*/
|
||||
static XPathExpression createXPathExpression(String expression) {
|
||||
try {
|
||||
XPath xpath = new XPath(expression, null, null, XPath.SELECT);
|
||||
return new XalanXPathExpression(xpath);
|
||||
}
|
||||
catch (TransformerException ex) {
|
||||
throw new org.springframework.xml.xpath.XPathParseException(
|
||||
"Could not compile [" + expression + "] to a XPathExpression: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Xalan <code>XPathExpression</code> from the given string expression and namespaces.
|
||||
*
|
||||
* @param expression the XPath expression
|
||||
* @return the compiled <code>XPathExpression</code>
|
||||
* @throws XPathParseException when the given expression cannot be parsed
|
||||
*/
|
||||
public static XPathExpression createXPathExpression(String expression, Map namespaces) {
|
||||
try {
|
||||
PrefixResolver prefixResolver = new SimplePrefixResolver(namespaces);
|
||||
XPath xpath = new XPath(expression, null, prefixResolver, XPath.SELECT);
|
||||
return new XalanXPathExpression(xpath);
|
||||
}
|
||||
catch (TransformerException ex) {
|
||||
throw new org.springframework.xml.xpath.XPathParseException(
|
||||
"Could not compile [" + expression + "] to a XPathExpression: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Xalan implementation of the <code>XPathExpression</code> interface.
|
||||
*/
|
||||
private static class XalanXPathExpression implements XPathExpression {
|
||||
|
||||
private XPath xpath;
|
||||
|
||||
private XPathContext context = new XPathContext();
|
||||
|
||||
private XalanXPathExpression(XPath xpath) {
|
||||
this.xpath = xpath;
|
||||
}
|
||||
|
||||
public Node evaluateAsNode(Node node) {
|
||||
try {
|
||||
XObject result = xpath.execute(context, node, null);
|
||||
NodeIterator iterator = result.nodeset();
|
||||
return iterator.nextNode();
|
||||
}
|
||||
catch (TransformerException ex) {
|
||||
throw new XPathException("Could not evaluate XPath expression:" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean evaluateAsBoolean(Node node) {
|
||||
try {
|
||||
XObject result = xpath.execute(context, node, null);
|
||||
return result.bool();
|
||||
}
|
||||
catch (TransformerException ex) {
|
||||
throw new XPathException("Could not evaluate XPath expression:" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public double evaluateAsNumber(Node node) {
|
||||
try {
|
||||
XObject result = xpath.execute(context, node, null);
|
||||
return result.num();
|
||||
}
|
||||
catch (TransformerException ex) {
|
||||
throw new XPathException("Could not evaluate XPath expression:" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String evaluateAsString(Node node) {
|
||||
try {
|
||||
XObject result = xpath.execute(context, node, null);
|
||||
return result.str();
|
||||
}
|
||||
catch (TransformerException ex) {
|
||||
throw new XPathException("Could not evaluate XPath expression:" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public Node[] evaluateAsNodes(Node node) {
|
||||
try {
|
||||
XObject result = xpath.execute(context, node, null);
|
||||
return toNodeArray(result.nodelist());
|
||||
}
|
||||
catch (TransformerException ex) {
|
||||
throw new XPathException("Could not evaluate XPath expression:" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Node[] toNodeArray(NodeList nodeList) {
|
||||
Node[] result = new Node[nodeList.getLength()];
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
result[i] = nodeList.item(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SimplePrefixResolver implements PrefixResolver {
|
||||
|
||||
private Map namespaces;
|
||||
|
||||
private SimplePrefixResolver(Map namespaces) {
|
||||
this.namespaces = namespaces;
|
||||
}
|
||||
|
||||
public String getNamespaceForPrefix(String prefix) {
|
||||
return (String) namespaces.get(prefix);
|
||||
}
|
||||
|
||||
public String getNamespaceForPrefix(String prefix, Node node) {
|
||||
return (String) namespaces.get(prefix);
|
||||
}
|
||||
|
||||
public String getBaseIdentifier() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean handlesNullPrefixes() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides classes for XPath evaluation using JAXP 1.3, Jaxen, and Xalan. Mostly for internal use by the framework.
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user