practicalxml-commits Mailing List for Practical XML (Page 10)
Brought to you by:
kdgregory
You can subscribe to this list here.
| 2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(6) |
Nov
(4) |
Dec
(35) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2009 |
Jan
(5) |
Feb
|
Mar
|
Apr
(7) |
May
|
Jun
|
Jul
(12) |
Aug
(24) |
Sep
(39) |
Oct
(16) |
Nov
(4) |
Dec
(7) |
| 2010 |
Jan
(10) |
Feb
|
Mar
(2) |
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
(4) |
Dec
(3) |
| 2011 |
Jan
(1) |
Feb
|
Mar
(1) |
Apr
(1) |
May
(3) |
Jun
|
Jul
|
Aug
(1) |
Sep
(10) |
Oct
(1) |
Nov
(1) |
Dec
(7) |
| 2012 |
Jan
(1) |
Feb
|
Mar
|
Apr
(1) |
May
(9) |
Jun
|
Jul
(5) |
Aug
(6) |
Sep
|
Oct
(1) |
Nov
|
Dec
|
| 2013 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(16) |
Jul
|
Aug
(6) |
Sep
(10) |
Oct
|
Nov
(2) |
Dec
|
| 2014 |
Jan
(5) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(2) |
Aug
|
Sep
|
Oct
(6) |
Nov
|
Dec
|
| 2015 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(5) |
| 2016 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-04-30 13:04:44
|
Revision: 82
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=82&view=rev
Author: kdgregory
Date: 2009-04-30 13:04:43 +0000 (Thu, 30 Apr 2009)
Log Message:
-----------
JavaDoc wants package.html to have HTML tags, was breaking site build ... who'da thunk
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/internal/package.html
Modified: trunk/src/main/java/net/sf/practicalxml/internal/package.html
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/internal/package.html 2009-04-30 12:08:58 UTC (rev 81)
+++ trunk/src/main/java/net/sf/practicalxml/internal/package.html 2009-04-30 13:04:43 UTC (rev 82)
@@ -1,4 +1,8 @@
-This package contains classes used internally by the PracticalXML library.
-Applications should not rely on the API of these classes, or indeed of their
-continued existence. In most cases, there's a better alternative in a third-
-party library.
\ No newline at end of file
+<html>
+<body>
+ This package contains classes used internally by the PracticalXML library.
+ Applications should not rely on the API of these classes, or indeed of their
+ continued existence. In most cases, there's a better alternative in a third-
+ party library.
+</body>
+</html>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-04-30 12:09:07
|
Revision: 81
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=81&view=rev
Author: kdgregory
Date: 2009-04-30 12:08:58 +0000 (Thu, 30 Apr 2009)
Log Message:
-----------
update logo usage per new SF policy
Modified Paths:
--------------
trunk/pom.xml
trunk/src/site/site.xml
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2009-04-28 17:54:17 UTC (rev 80)
+++ trunk/pom.xml 2009-04-30 12:08:58 UTC (rev 81)
@@ -83,7 +83,7 @@
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<bottom>
- <a href="http://sourceforge.net/">
+ <a href="http://sourceforge.net/projects/practicalxml/">
<img src="http://sflogo.sourceforge.net/sflogo.php?group_id=234884&type=3">
</a>
</bottom>
Modified: trunk/src/site/site.xml
===================================================================
--- trunk/src/site/site.xml 2009-04-28 17:54:17 UTC (rev 80)
+++ trunk/src/site/site.xml 2009-04-30 12:08:58 UTC (rev 81)
@@ -7,7 +7,7 @@
href="http://maven.apache.org/"
img="http://maven.apache.org/images/logos/maven-feather.png"/>
<logo name="SourceForge"
- href="http://sourceforge.net/"
+ href="http://sourceforge.net/projects/practicalxml/"
img="http://sflogo.sourceforge.net/sflogo.php?group_id=234884&type=3"/>
</poweredBy>
</project>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-04-28 17:54:28
|
Revision: 80
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=80&view=rev
Author: kdgregory
Date: 2009-04-28 17:54:17 +0000 (Tue, 28 Apr 2009)
Log Message:
-----------
XmlBuilder: output routines now properly handle comments (using SAX extension class)
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/builder/CommentNode.java
trunk/src/main/java/net/sf/practicalxml/builder/ElementNode.java
trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilder.java
trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java
Modified: trunk/src/main/java/net/sf/practicalxml/builder/CommentNode.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/CommentNode.java 2009-04-27 12:41:46 UTC (rev 79)
+++ trunk/src/main/java/net/sf/practicalxml/builder/CommentNode.java 2009-04-28 17:54:17 UTC (rev 80)
@@ -16,6 +16,9 @@
import org.w3c.dom.Comment;
import org.w3c.dom.Element;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
/**
@@ -40,4 +43,14 @@
Comment node = parent.getOwnerDocument().createComment(_content);
parent.appendChild(node);
}
+
+
+ @Override
+ protected void toSAX(ContentHandler handler) throws SAXException
+ {
+ if (handler instanceof LexicalHandler)
+ {
+ ((LexicalHandler)handler).comment(_content.toCharArray(), 0, _content.length());
+ }
+ }
}
Modified: trunk/src/main/java/net/sf/practicalxml/builder/ElementNode.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/ElementNode.java 2009-04-27 12:41:46 UTC (rev 79)
+++ trunk/src/main/java/net/sf/practicalxml/builder/ElementNode.java 2009-04-28 17:54:17 UTC (rev 80)
@@ -85,8 +85,10 @@
/**
- * Invokes the passed <code>ContentHandler</code> for this element
- * and its children.
+ * Invokes the passed <code>ContentHandler</code> for this element and
+ * its children. Note that the implementation class must also implement
+ * <code>LexicalHandler</code> to receive events from all nodes in the
+ * tree (particularly comments).
*/
@Override
protected void toSAX(ContentHandler handler)
@@ -106,12 +108,6 @@
* not insert whitespace between elements. Note that you <em>must</em>
* use UTF-8 encoding or add a prologue that specifies encoding when
* writing this string to a stream.
- * <p>
- * <em>Warning:</em>
- * This method uses a SAX transformer, to minimize footprint. However,
- * SAX does not support comment modes, so they will be silently dropped.
- * If they are important to you, call {@link #toDOM} and use {@link
- * net.sf.practicalxml.OutputUtil#compactString} to generate output.
*/
@Override
public String toString()
@@ -128,12 +124,6 @@
* This is the best choice for writing log output. If you write this string
* to a stream, you <em>must</em> use UTF-8 encoding or attach a prologue
* that specifies the encoding used.
- * <p>
- * <em>Warning:</em>
- * This method uses a SAX transformer, to minimize footprint. However,
- * SAX does not support comment modes, so they will be silently dropped.
- * If they are important to you, call {@link #toDOM} and use {@link
- * net.sf.practicalxml.OutputUtil#indentedString} to generate output.
*/
public String toString(int indentSize)
{
@@ -147,12 +137,6 @@
* <p>
* This is the best choice for writing XML that will be read by another
* party.
- * <p>
- * <em>Warning:</em>
- * This method uses a SAX transformer, to minimize footprint. However,
- * SAX does not support comment modes, so they will be silently dropped.
- * If they are important to you, call {@link #toDOM} and use {@link
- * net.sf.practicalxml.OutputUtil#compactStream} to generate output.
*/
public void toStream(OutputStream out)
{
@@ -164,12 +148,6 @@
* Writes the tree rooted at this element to an <code>OutputStream</code>,
* using a specified encoding, without a prologue or whitepspace between
* nodes.
- * <p>
- * <em>Warning:</em>
- * This method uses a SAX transformer, to minimize footprint. However,
- * SAX does not support comment modes, so they will be silently dropped.
- * If they are important to you, call {@link #toDOM} and use {@link
- * net.sf.practicalxml.OutputUtil#compactStream} to generate output.
*/
public void toStream(OutputStream out, String encoding)
{
Modified: trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilder.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilder.java 2009-04-27 12:41:46 UTC (rev 79)
+++ trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilder.java 2009-04-28 17:54:17 UTC (rev 80)
@@ -97,9 +97,9 @@
/**
* Creates a comment node.
* <p>
- * <em>Warning</em>:
- * Comment nodes are not reported by SAX sources. If comments are
- * important to you, convert to DOM before serialization.
+ * <em>Warning:</em>
+ * Comment nodes are only reported to SAX content handlers that also
+ * implement <code>org.xml.sax.ext.LexicalHandler</code>.
*/
public static Node comment(String text)
{
Modified: trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java 2009-04-27 12:41:46 UTC (rev 79)
+++ trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java 2009-04-28 17:54:17 UTC (rev 80)
@@ -32,6 +32,7 @@
import org.w3c.dom.ProcessingInstruction;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
+import org.xml.sax.ext.LexicalHandler;
import net.sf.practicalxml.AbstractTestCase;
import net.sf.practicalxml.DomUtil;
@@ -72,7 +73,7 @@
{
return (ContentHandler)Proxy.newProxyInstance(
ContentHandler.class.getClassLoader(),
- new Class[] { ContentHandler.class },
+ new Class[] { ContentHandler.class, LexicalHandler.class },
this);
}
@@ -82,7 +83,7 @@
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
- // this is a hack for characters
+ // this is a hack for characters() and comment()
for (int ii = 0 ; ii < args.length ; ii++)
{
if (args[ii] instanceof char[])
@@ -276,11 +277,11 @@
// note: ContentHandler knows nothing of comments
MockContentHandler handler = new MockContentHandler();
node.toSAX(handler.getHandler());
- handler.assertInvocationSequence("startElement", "endElement");
+ handler.assertInvocationSequence("startElement", "comment", "endElement");
handler.assertInvocation(0, "startElement", null, "foo", "foo");
+ handler.assertInvocation(1, "comment", "bar", 0, 3);
-
-// assertEquals("<foo><!--bar--></foo>", node.toString());
+ assertEquals("<foo><!--bar--></foo>", node.toString());
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-04-27 12:41:56
|
Revision: 79
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=79&view=rev
Author: kdgregory
Date: 2009-04-27 12:41:46 +0000 (Mon, 27 Apr 2009)
Log Message:
-----------
OutputUtil: added support for XMLReader as input source
XmlBuilder: use SAX for output (lowers footprint, discards comments)
support Processing Instruction nodes (not that anyone uses them)
added better package comment
Modified Paths:
--------------
trunk/pom.xml
trunk/src/main/java/net/sf/practicalxml/OutputUtil.java
trunk/src/main/java/net/sf/practicalxml/builder/AttributeNode.java
trunk/src/main/java/net/sf/practicalxml/builder/CommentNode.java
trunk/src/main/java/net/sf/practicalxml/builder/ElementNode.java
trunk/src/main/java/net/sf/practicalxml/builder/Node.java
trunk/src/main/java/net/sf/practicalxml/builder/TextNode.java
trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilder.java
trunk/src/main/java/net/sf/practicalxml/builder/package.html
trunk/src/test/java/net/sf/practicalxml/TestOutputUtil.java
trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java
Added Paths:
-----------
trunk/src/main/java/net/sf/practicalxml/builder/PINode.java
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2009-04-25 13:59:44 UTC (rev 78)
+++ trunk/pom.xml 2009-04-27 12:41:46 UTC (rev 79)
@@ -5,7 +5,7 @@
<groupId>net.sf.practicalxml</groupId>
<artifactId>practicalxml</artifactId>
<packaging>jar</packaging>
- <version>1.0.1</version>
+ <version>1.0.2</version>
<name>practicalxml</name>
<url>http://sourceforge.net/projects/practicalxml/</url>
Modified: trunk/src/main/java/net/sf/practicalxml/OutputUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/OutputUtil.java 2009-04-25 13:59:44 UTC (rev 78)
+++ trunk/src/main/java/net/sf/practicalxml/OutputUtil.java 2009-04-27 12:41:46 UTC (rev 79)
@@ -25,10 +25,12 @@
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 org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.xml.sax.XMLReader;
/**
@@ -42,7 +44,8 @@
/**
* A simple <code>toString()</code> for an element, using the format
* "<code>{<i>NSURI</i>}<i>LOCALNAME</i></code>"; if the element has no
- * namespace, the brackets remain but are empty.
+ * namespace, the brackets remain but are empty. This is typically used
+ * for debugging.
*/
public static String elementToString(Element elem)
{
@@ -51,12 +54,8 @@
/**
- * Debug dump of the tree rooted at the specified element. Each line holds
- * one element,
- *
- *
- * @param elem
- * @param indent
+ * Debug dump of the e rooted at the specified element. Each line holds
+ * one element, and elements are formatted per {@link #elementToString}.
*/
public static String treeToString(Element elem, int indent)
{
@@ -68,7 +67,6 @@
* Writes a DOM document to a simple string format, without a prologue or
* whitespace between elements.
* <p>
- *
* Do not simply write this string to a file unless you use UTF-8 encoding
* or attach a prologue that specifies your actual encoding.
*
@@ -84,10 +82,38 @@
/**
+ * Writes XML in a simple string format, without prologue or whitespace
+ * between elements, using the passed <code>XMLReader</code> to generate
+ * a stream of SAX events.
+ * <p>
+ * The transformer will call the reader's <code>setContentHandler()</code>
+ * method, followed by <code>parse()</code>. In the latter method, the
+ * reader must invoke the content handler's event methods in the correct
+ * order: at the very least, <code>startDocument() </code>, followed by
+ * <code>startElement()</code> and <code>endElement()</code> for the root
+ * element, finishing with <code>endDocument()</code>. Note that SAX does
+ * not support all DOM node types: in particular, there are no comments.
+ * <p>
+ * Do not simply write this string to a file unless you use UTF-8 encoding
+ * or attach a prologue that specifies your actual encoding.
+ *
+ * @param reader Provides a source of SAX events for the transformer.
+ */
+ public static String compactString(XMLReader reader)
+ {
+ StringWriter out = new StringWriter();
+ new TransformHelper()
+ .transform(new SAXSource(reader, null), new StreamResult(out));
+ return out.toString();
+ }
+
+
+ /**
* Writes a DOM document to a string format, with indenting between
- * elements but without a prologue. Do not simply write this string
- * to a file unless you use UTF-8 encoding or attach a prologue that
- * specifies the encoding.
+ * elements but without a prologue.
+ * <p>
+ * Do not simply write this string to a file unless you use UTF-8 encoding
+ * or attach a prologue that specifies the encoding.
*
* @param dom The DOM tree to be output.
* @param indentSize The number of spaces to indent each level of the
@@ -110,9 +136,45 @@
/**
- * Writes a DOM document to a stream, without a prologue or whitespace
- * between elements, and using UTF-8 encoding.
+ * Writes XML in a simple string format, without prologue or whitespace
+ * between elements, using the passed <code>XMLReader</code> to generate
+ * a stream of SAX events.
+ * <p>
+ * The transformer will call the reader's <code>setContentHandler()</code>
+ * method, followed by <code>parse()</code>. In the latter method, the
+ * reader must invoke the content handler's event methods in the correct
+ * order: at the very least, <code>startDocument() </code>, followed by
+ * <code>startElement()</code> and <code>endElement()</code> for the root
+ * element, finishing with <code>endDocument()</code>. Note that SAX does
+ * not support all DOM node types: in particular, there are no comments.
+ * <p>
+ * Do not simply write this string to a file unless you use UTF-8 encoding
+ * or attach a prologue that specifies the encoding.
*
+ * @param reader Provides a source of SAX events for the transformer.
+ * @param indentSize The number of spaces to indent each level of the
+ * tree. Indentation is <em>best effort</em>: the
+ * <code>javax.transform</code> API does not provide
+ * any way to set indent level, so we use JDK-specific
+ * features to achieve this, <em>where available</em>.
+ * Note also that indenting will cause problems with
+ * elements that contain mixed content, particularly
+ * if the text elements cannot be trimmed.
+ */
+ public static String indentedString(XMLReader reader, int indentSize)
+ {
+ StringWriter out = new StringWriter();
+ new TransformHelper()
+ .setIndent(indentSize)
+ .transform(new SAXSource(reader, null), new StreamResult(out));
+ return out.toString();
+ }
+
+
+ /**
+ * Writes a DOM document to a stream using UTF-8 encoding, without a prologue
+ * or whitespace between elements.
+ *
* @param dom The DOM tree to be output.
* @param stream The output stream. This stream will be flushed by
* this method, but will <em>not</em> be closed.
@@ -126,6 +188,31 @@
/**
+ * Writes XML to a stream using UTF-8 encoding, without prologue or
+ * whitespace between elements, using the passed <code>XMLReader</code>
+ * to generate a stream of SAX events.
+ * <p>
+ * The transformer will call the reader's <code>setContentHandler()</code>
+ * method, followed by <code>parse()</code>. In the latter method, the
+ * reader must invoke the content handler's event methods in the correct
+ * order: at the very least, <code>startDocument() </code>, followed by
+ * <code>startElement()</code> and <code>endElement()</code> for the root
+ * element, finishing with <code>endDocument()</code>. Note that SAX does
+ * not support all DOM node types: in particular, there are no comments.
+ *
+ * @param reader Provides a source of SAX events for the transformer.
+ * @param stream The output stream. This stream will be flushed by
+ * this method, but will <em>not</em> be closed.
+ */
+ public static void compactStream(XMLReader reader, OutputStream stream)
+ {
+ new TransformHelper()
+ .transform(new SAXSource(reader, null), new StreamResult(stream));
+ flushStream(stream);
+ }
+
+
+ /**
* Writes a DOM document to a stream using the specified encoding, without
* whitespace between elements, but <em>with</em> a prologue that specifes
* the encoding.
@@ -144,6 +231,32 @@
/**
+ * Writes XML to a stream using the specified encoding, without prologue or
+ * whitespace between elements, using the passed <code>XMLReader</code>
+ * to generate a stream of SAX events.
+ * <p>
+ * The transformer will call the reader's <code>setContentHandler()</code>
+ * method, followed by <code>parse()</code>. In the latter method, the
+ * reader must invoke the content handler's event methods in the correct
+ * order: at the very least, <code>startDocument() </code>, followed by
+ * <code>startElement()</code> and <code>endElement()</code> for the root
+ * element, finishing with <code>endDocument()</code>. Note that SAX does
+ * not support all DOM node types: in particular, there are no comments.
+ *
+ * @param reader Provides a source of SAX events for the transformer.
+ * @param stream The output stream. This stream will be flushed by
+ * this method, but will <em>not</em> be closed.
+ */
+ public static void compactStream(XMLReader reader, OutputStream stream, String encoding)
+ {
+ new TransformHelper()
+ .setPrologue(encoding)
+ .transform(new SAXSource(reader, null), new StreamResult(stream));
+ flushStream(stream);
+ }
+
+
+ /**
* This object does the actual transformation work; the exposed static
* methods create and configure an instance to do their job. If you
* need finer control over output, you can do the same: call the various
Modified: trunk/src/main/java/net/sf/practicalxml/builder/AttributeNode.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/AttributeNode.java 2009-04-25 13:59:44 UTC (rev 78)
+++ trunk/src/main/java/net/sf/practicalxml/builder/AttributeNode.java 2009-04-27 12:41:46 UTC (rev 79)
@@ -15,6 +15,7 @@
package net.sf.practicalxml.builder;
import org.w3c.dom.Element;
+import org.xml.sax.helpers.AttributesImpl;
/**
@@ -24,16 +25,18 @@
extends Node
implements java.io.Serializable
{
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
private String _nsUri;
private String _qname;
+ private String _lclName;
private String _value;
public AttributeNode(String nsUri, String qname, String value)
{
_nsUri = nsUri;
_qname = qname;
+ _lclName = getLocalName(qname);
_value = value;
}
@@ -46,4 +49,14 @@
else
parent.setAttributeNS(_nsUri, _qname, _value);
}
+
+
+ /**
+ * Helper method to produce a SAX <code>Attributes</code> object. This
+ * is called by ElementNode.
+ */
+ protected void appendToAttributes(AttributesImpl attrs)
+ {
+ attrs.addAttribute(_nsUri, _lclName, _qname, "", _value);
+ }
}
Modified: trunk/src/main/java/net/sf/practicalxml/builder/CommentNode.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/CommentNode.java 2009-04-25 13:59:44 UTC (rev 78)
+++ trunk/src/main/java/net/sf/practicalxml/builder/CommentNode.java 2009-04-27 12:41:46 UTC (rev 79)
@@ -18,6 +18,9 @@
import org.w3c.dom.Element;
+/**
+ * Holds a comment.
+ */
public class CommentNode
extends Node
{
Modified: trunk/src/main/java/net/sf/practicalxml/builder/ElementNode.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/ElementNode.java 2009-04-25 13:59:44 UTC (rev 78)
+++ trunk/src/main/java/net/sf/practicalxml/builder/ElementNode.java 2009-04-27 12:41:46 UTC (rev 79)
@@ -14,71 +14,130 @@
package net.sf.practicalxml.builder;
+import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.XMLFilterImpl;
import net.sf.practicalxml.DomUtil;
import net.sf.practicalxml.OutputUtil;
+/**
+ * The primary class for building XML trees and converting them to different
+ * JAXP-centric forms. Callers should not create instances of this class
+ * directly; instead use the static factory methods in {@link XmlBuilder}.
+ */
public final class ElementNode
extends Node
{
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
- private String _nsUri;
- private String _qname;
- private List<Node> _children;
+ private String _nsUri;
+ private String _qname;
+ private String _lclName;
+ private List<AttributeNode> _attribs = new ArrayList<AttributeNode>();
+ private List<Node> _children = new ArrayList<Node>();
+
ElementNode(String nsUri, String qname, Node... children)
{
_nsUri = nsUri;
_qname = qname;
- _children = new ArrayList<Node>(Arrays.asList(children));
+ _lclName = getLocalName(qname);
+ for (Node child : children)
+ addChild(child);
}
/**
- * Adds a child node -- of any type -- to this element.
+ * Adds a child node -- of any type -- to this element. Returns this as
+ * a convenience to caller, allowing calls to be chained.
*/
public ElementNode addChild(Node child)
{
- if (child != null)
+ if (child instanceof AttributeNode)
+ _attribs.add((AttributeNode)child);
+ else if (child != null)
_children.add(child);
return this;
}
/**
+ * Generates a new DOM document with this element as the root.
+ */
+ public Document toDOM()
+ {
+ Element root = DomUtil.newDocument(_nsUri, _qname);
+ appendChildren(root);
+ return root.getOwnerDocument();
+ }
+
+
+ /**
+ * Invokes the passed <code>ContentHandler</code> for this element
+ * and its children.
+ */
+ @Override
+ protected void toSAX(ContentHandler handler)
+ throws SAXException
+ {
+ handler.startElement(_nsUri, _lclName, _qname, getAttributes());
+ for (Node child : _children)
+ {
+ child.toSAX(handler);
+ }
+ handler.endElement(_nsUri, _lclName, _qname);
+ }
+
+
+ /**
* Generates an XML string, where this node is the root element. Does
- * not insert whitespace between elements.
+ * not insert whitespace between elements. Note that you <em>must</em>
+ * use UTF-8 encoding or add a prologue that specifies encoding when
+ * writing this string to a stream.
* <p>
- * If you write this string to a file, you <em>must</em> use UTF-8
- * encoding or attach a prologue that specifies the encoding used.
+ * <em>Warning:</em>
+ * This method uses a SAX transformer, to minimize footprint. However,
+ * SAX does not support comment modes, so they will be silently dropped.
+ * If they are important to you, call {@link #toDOM} and use {@link
+ * net.sf.practicalxml.OutputUtil#compactString} to generate output.
*/
@Override
public String toString()
{
- return OutputUtil.compactString(toDOM());
+ return OutputUtil.compactString(new SerializationHelper());
}
/**
* Generates an XML string, where this node is the root element. Inserts
- * whitespace between nodes, with the specified indent size.
+ * whitespace between nodes, along with newlines and the specified indent
+ * between elements.
* <p>
* This is the best choice for writing log output. If you write this string
* to a stream, you <em>must</em> use UTF-8 encoding or attach a prologue
* that specifies the encoding used.
+ * <p>
+ * <em>Warning:</em>
+ * This method uses a SAX transformer, to minimize footprint. However,
+ * SAX does not support comment modes, so they will be silently dropped.
+ * If they are important to you, call {@link #toDOM} and use {@link
+ * net.sf.practicalxml.OutputUtil#indentedString} to generate output.
*/
public String toString(int indentSize)
{
- return OutputUtil.indentedString(toDOM(), indentSize);
+ return OutputUtil.indentedString(new SerializationHelper(), indentSize);
}
@@ -88,10 +147,16 @@
* <p>
* This is the best choice for writing XML that will be read by another
* party.
+ * <p>
+ * <em>Warning:</em>
+ * This method uses a SAX transformer, to minimize footprint. However,
+ * SAX does not support comment modes, so they will be silently dropped.
+ * If they are important to you, call {@link #toDOM} and use {@link
+ * net.sf.practicalxml.OutputUtil#compactStream} to generate output.
*/
public void toStream(OutputStream out)
{
- OutputUtil.compactStream(toDOM(), out);
+ OutputUtil.compactStream(new SerializationHelper(), out);
}
@@ -99,6 +164,12 @@
* Writes the tree rooted at this element to an <code>OutputStream</code>,
* using a specified encoding, without a prologue or whitepspace between
* nodes.
+ * <p>
+ * <em>Warning:</em>
+ * This method uses a SAX transformer, to minimize footprint. However,
+ * SAX does not support comment modes, so they will be silently dropped.
+ * If they are important to you, call {@link #toDOM} and use {@link
+ * net.sf.practicalxml.OutputUtil#compactStream} to generate output.
*/
public void toStream(OutputStream out, String encoding)
{
@@ -106,27 +177,51 @@
}
- /**
- * Generates a new DOM document, with this element as the root.
- */
- public Document toDOM()
+//----------------------------------------------------------------------------
+// Internals
+//----------------------------------------------------------------------------
+
+ @Override
+ protected void appendToElement(Element parent)
{
- Element root = DomUtil.newDocument(_nsUri, _qname);
+ appendChildren(DomUtil.appendChild(parent, _nsUri, _qname));
+ }
+
+
+ private void appendChildren(Element elem)
+ {
+ for (Node child : _attribs)
+ {
+ child.appendToElement(elem);
+ }
for (Node child : _children)
{
- child.appendToElement(root);
+ child.appendToElement(elem);
}
- return root.getOwnerDocument();
}
- @Override
- protected void appendToElement(Element parent)
+ private Attributes getAttributes()
{
- Element elem = DomUtil.appendChild(parent, _nsUri, _qname);
- for (Node child : _children)
+ AttributesImpl result = new AttributesImpl();
+ for (AttributeNode attr : _attribs)
{
- child.appendToElement(elem);
+ attr.appendToAttributes(result);
}
+ return result;
}
+
+
+ private class SerializationHelper
+ extends XMLFilterImpl
+ {
+ @Override
+ public void parse(InputSource input)
+ throws SAXException, IOException
+ {
+ startDocument();
+ toSAX(getContentHandler());
+ endDocument();
+ }
+ }
}
Modified: trunk/src/main/java/net/sf/practicalxml/builder/Node.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/Node.java 2009-04-25 13:59:44 UTC (rev 78)
+++ trunk/src/main/java/net/sf/practicalxml/builder/Node.java 2009-04-27 12:41:46 UTC (rev 79)
@@ -15,6 +15,8 @@
package net.sf.practicalxml.builder;
import org.w3c.dom.Element;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
/**
@@ -23,15 +25,40 @@
* are immutable, and require their parent to provide context (ie, no back-
* pointers).
* <p>
- * <code>Node</code> is defined as an abstract class because all methods are
- * internal. Only <code>ElementNode</code> should define public methods.
+ * <code>Node</code> is defined as an abstract class (rather than an interface)
+ * to allow declaration of protected methods and to provide helper methods.
*/
public abstract class Node
implements java.io.Serializable
{
/**
* This method is called internally by {@link ElementNode}, to append
- * its children.
+ * its children to the DOM subtree rooted at the specified element.
*/
protected abstract void appendToElement(Element elem);
+
+
+ /**
+ * Invokes the passed <code>ContentHandler</code> for this element
+ * and its children. Default implementation does nothing (appropriate
+ * for attributes only).
+ */
+ protected void toSAX(ContentHandler handler)
+ throws SAXException
+ {
+ // nothing happening here ... but almost everyone should override
+ }
+
+
+ /**
+ * Utility method to return a local name from either a qualified or
+ * non-qualified name.
+ */
+ protected static String getLocalName(String qname)
+ {
+ int sepIdx = qname.indexOf(':');
+ return (sepIdx < 0)
+ ? qname
+ : qname.substring(sepIdx + 1);
+ }
}
Added: trunk/src/main/java/net/sf/practicalxml/builder/PINode.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/PINode.java (rev 0)
+++ trunk/src/main/java/net/sf/practicalxml/builder/PINode.java 2009-04-27 12:41:46 UTC (rev 79)
@@ -0,0 +1,54 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.builder;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.ProcessingInstruction;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Holds a processing instruction.
+ */
+public class PINode extends Node
+{
+ private static final long serialVersionUID = 1L;
+
+ private String _target;
+ private String _data;
+
+ public PINode(String target, String data)
+ {
+ _target = target;
+ _data = data;
+ }
+
+
+ @Override
+ protected void appendToElement(Element parent)
+ {
+ ProcessingInstruction pi = parent.getOwnerDocument()
+ .createProcessingInstruction(_target, _data);
+ parent.appendChild(pi);
+ }
+
+
+ @Override
+ protected void toSAX(ContentHandler handler) throws SAXException
+ {
+ handler.processingInstruction(_target, _data);
+ }
+}
Modified: trunk/src/main/java/net/sf/practicalxml/builder/TextNode.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/TextNode.java 2009-04-25 13:59:44 UTC (rev 78)
+++ trunk/src/main/java/net/sf/practicalxml/builder/TextNode.java 2009-04-27 12:41:46 UTC (rev 79)
@@ -15,10 +15,16 @@
package net.sf.practicalxml.builder;
import org.w3c.dom.Element;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
import net.sf.practicalxml.DomUtil;
+/**
+ * Holds element content. Will be converted to DOM as <code>Text</code>
+ * (not <code>CDATASection</code>).
+ */
public class TextNode extends Node
{
private static final long serialVersionUID = 1L;
@@ -36,4 +42,11 @@
{
DomUtil.appendText(parent, _content);
}
+
+
+ @Override
+ protected void toSAX(ContentHandler handler) throws SAXException
+ {
+ handler.characters(_content.toCharArray(), 0, _content.length());
+ }
}
Modified: trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilder.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilder.java 2009-04-25 13:59:44 UTC (rev 78)
+++ trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilder.java 2009-04-27 12:41:46 UTC (rev 79)
@@ -96,9 +96,22 @@
/**
* Creates a comment node.
+ * <p>
+ * <em>Warning</em>:
+ * Comment nodes are not reported by SAX sources. If comments are
+ * important to you, convert to DOM before serialization.
*/
public static Node comment(String text)
{
return new CommentNode(text);
}
+
+
+ /**
+ * Creates a processing instruction node.
+ */
+ public static Node processingInstruction(String target, String data)
+ {
+ return new PINode(target, data);
+ }
}
Modified: trunk/src/main/java/net/sf/practicalxml/builder/package.html
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/package.html 2009-04-25 13:59:44 UTC (rev 78)
+++ trunk/src/main/java/net/sf/practicalxml/builder/package.html 2009-04-27 12:41:46 UTC (rev 79)
@@ -1,5 +1,31 @@
<html>
<body>
- This package contains a tool for declarative creation of XML documents.
+ <code>XmlBuilder</code> is a tool for declarative construction of XML.
+ It was originally created to generate XML for unit tests, but is useful
+ wherever you want to construct XML documents with minimal code and a
+ low memory footprint.
+ <p>
+ The two classes of interest are {@link net.sf.practicalxml.builder.ElementNode}
+ and {@link net.sf.practicalxml.builder.XmlBuilder}: the former contains public
+ methods for transforming a tree into various representations, while the latter
+ contains static methods for building such a tree:
+
+ <pre>
+ import static net.sf.practicalxml.builder.XmlBuilder.*;
+
+ // ...
+
+ ElementNode root =
+ element("root",
+ element("child1",
+ text("this is some <text>")),
+ element("child2",
+ attribute("foo", "bar"),
+ attribute("baz", "biff")),
+ element("http::www.example.com/foo", "ns:child3"));
+
+ Document dom = root.toDOM();
+ String out = root.toString();
+ </pre>
</body>
</html>
\ No newline at end of file
Modified: trunk/src/test/java/net/sf/practicalxml/TestOutputUtil.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestOutputUtil.java 2009-04-25 13:59:44 UTC (rev 78)
+++ trunk/src/test/java/net/sf/practicalxml/TestOutputUtil.java 2009-04-27 12:41:46 UTC (rev 79)
@@ -15,7 +15,13 @@
package net.sf.practicalxml;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
import org.w3c.dom.Element;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLFilterImpl;
public class TestOutputUtil
@@ -44,6 +50,33 @@
public final static String SOME_TEXT = "blah";
+ /**
+ * An XMLReader that emits a specified series of nested tags.
+ */
+ private static class MyXMLReader
+ extends XMLFilterImpl
+ {
+ private String[] _elems;
+
+ public MyXMLReader(String... elems)
+ {
+ _elems = elems;
+ }
+
+ @Override
+ public void parse(InputSource input)
+ throws SAXException, IOException
+ {
+ getContentHandler().startDocument();
+ for (int ii = 0 ; ii < _elems.length ; ii++)
+ getContentHandler().startElement(null, _elems[ii], _elems[ii], null);
+ for (int ii = _elems.length -1 ; ii >= 0 ; ii--)
+ getContentHandler().endElement(null, _elems[ii], _elems[ii]);
+ getContentHandler().endDocument();
+ }
+ }
+
+
//----------------------------------------------------------------------------
// Test Cases -- in most of these tests we look for overall structure, assume
// that the output transform will do the right thing
@@ -69,7 +102,7 @@
}
- public void testCompactStringSingleElement() throws Exception
+ public void testCompactStringSingleElementDOM() throws Exception
{
Element root = DomUtil.newDocument(EL_ROOT);
@@ -78,7 +111,7 @@
}
- public void testCompactStringParentChild() throws Exception
+ public void testCompactStringParentChildDOM() throws Exception
{
Element root = DomUtil.newDocument(EL_ROOT);
DomUtil.appendChild(root, EL_CHILD);
@@ -88,6 +121,22 @@
}
+ public void testCompactStringSingleElementSAX() throws Exception
+ {
+ XMLReader reader = new MyXMLReader(EL_ROOT);
+ String s = OutputUtil.compactString(reader);
+ assertEquals(EL_ROOT_SOLO, s);
+ }
+
+
+ public void testCompactStringParentChildSAX() throws Exception
+ {
+ XMLReader reader = new MyXMLReader(EL_ROOT, EL_CHILD);
+ String s = OutputUtil.compactString(reader);
+ assertEquals(EL_ROOT_START + EL_CHILD_SOLO + EL_ROOT_END, s);
+ }
+
+
public void testCompactStringWithText() throws Exception
{
Element root = DomUtil.newDocument(EL_ROOT);
@@ -98,6 +147,29 @@
}
+ public void testIndentedStringParentChildDOM() throws Exception
+ {
+ Element root = DomUtil.newDocument(EL_ROOT);
+ Element child = DomUtil.appendChild(root, EL_CHILD);
+ DomUtil.setText(child, SOME_TEXT);
+
+ String s = OutputUtil.indentedString(root.getOwnerDocument(), 4);
+ assertMultiline(EL_ROOT_START
+ + "\n " + EL_CHILD_START + SOME_TEXT + EL_CHILD_END
+ + "\n" + EL_ROOT_END + "\n", s);
+ }
+
+
+ public void testIndentedStringParentChildSAX() throws Exception
+ {
+ XMLReader reader = new MyXMLReader(EL_ROOT, EL_CHILD);
+ String s = OutputUtil.indentedString(reader, 4);
+ assertMultiline(EL_ROOT_START
+ + "\n " + EL_CHILD_SOLO
+ + "\n" + EL_ROOT_END + "\n", s);
+ }
+
+
public void testIndentedStringParentChildText() throws Exception
{
Element root = DomUtil.newDocument(EL_ROOT);
@@ -111,7 +183,7 @@
}
- public void testCompactStreamAsciiContent() throws Exception
+ public void testCompactStreamAsciiContentDOM() throws Exception
{
Element root = DomUtil.newDocument("foo");
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -128,6 +200,23 @@
}
+ public void testCompactStreamAsciiContentSAX() throws Exception
+ {
+ XMLReader reader = new MyXMLReader("foo");
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ OutputUtil.compactStream(reader, out);
+ byte[] data = out.toByteArray();
+ assertEquals(6, data.length);
+ assertEquals('<', data[0]);
+ assertEquals('f', data[1]);
+ assertEquals('o', data[2]);
+ assertEquals('o', data[3]);
+ assertEquals('/', data[4]);
+ assertEquals('>', data[5]);
+ }
+
+
public void testCompactStreamNonAsciiDefaultEncoding() throws Exception
{
Element root = DomUtil.newDocument("\u00C0\u00C1");
@@ -147,7 +236,7 @@
}
- public void testCompactStreamNonAsciiISO8859Encoding() throws Exception
+ public void testCompactStreamNonAsciiISO8859EncodingDOM() throws Exception
{
Element root = DomUtil.newDocument("\u00C0\u00C1");
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -169,6 +258,30 @@
assertTrue("no encoding", s.indexOf("encoding") > 0);
assertTrue("incorrect encoding",
s.indexOf("iso-8859-1") > 0 || s.indexOf("ISO-8859-1") > 0);
+ }
+
+ public void testCompactStreamNonAsciiISO8859EncodingSAX() throws Exception
+ {
+ XMLReader reader = new MyXMLReader("\u00C0\u00C1");
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ OutputUtil.compactStream(reader, out, "ISO-8859-1");
+ byte[] data = out.toByteArray();
+
+ // look for specific bytes for the element ... note reverse order
+ int idx = data.length - 1;
+ assertEquals('>', data[idx--]);
+ assertEquals('/', data[idx--]);
+ assertEquals(0xC1, data[idx--] & 0xFF);
+ assertEquals(0xC0, data[idx--] & 0xFF);
+ assertEquals('<', data[idx]);
+
+ // convert to string to check for prologue
+ String s = new String(data, "ISO-8859-1");
+ assertTrue("no prologue", s.startsWith("<?xml"));
+ assertTrue("no encoding", s.indexOf("encoding") > 0);
+ assertTrue("incorrect encoding",
+ s.indexOf("iso-8859-1") > 0 || s.indexOf("ISO-8859-1") > 0);
}
}
Modified: trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java 2009-04-25 13:59:44 UTC (rev 78)
+++ trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java 2009-04-27 12:41:46 UTC (rev 79)
@@ -15,6 +15,12 @@
package net.sf.practicalxml.builder;
import java.io.ByteArrayOutputStream;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
@@ -23,6 +29,9 @@
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.ProcessingInstruction;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
import net.sf.practicalxml.AbstractTestCase;
import net.sf.practicalxml.DomUtil;
@@ -55,6 +64,71 @@
}
+ private static class MockContentHandler
+ implements InvocationHandler
+ {
+ public ContentHandler getHandler()
+ throws Exception
+ {
+ return (ContentHandler)Proxy.newProxyInstance(
+ ContentHandler.class.getClassLoader(),
+ new Class[] { ContentHandler.class },
+ this);
+ }
+
+ private ArrayList<String> _names = new ArrayList<String>();
+ private ArrayList<Object[]> _args = new ArrayList<Object[]>();
+
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable
+ {
+ // this is a hack for characters
+ for (int ii = 0 ; ii < args.length ; ii++)
+ {
+ if (args[ii] instanceof char[])
+ args[ii] = new String((char[])args[ii]);
+ }
+
+ _names.add(method.getName());
+ _args.add(args);
+ return null;
+ }
+
+ /**
+ * Asserts that the specific sequence of methods was called on this
+ * handler.
+ */
+ public void assertInvocationSequence(String... methodNames)
+ {
+ List<String> expected = Arrays.asList(methodNames);
+ assertEquals(expected, _names);
+ }
+
+ /**
+ * Asserts the name and argument values for a specific call to this
+ * handler. For convenience, ignores any arguments past the expected
+ * list.
+ */
+ public void assertInvocation(int callNum, String methodName, Object... args)
+ {
+ assertEquals(methodName, _names.get(callNum));
+ for (int ii = 0 ; ii < args.length ; ii++)
+ {
+ assertEquals("argument " + ii, args[ii], _args.get(callNum)[ii]);
+ }
+ }
+
+ /**
+ * Returns a specific argument passed to a specific invocation. This
+ * allows the caller to make test-specific assertions.
+ */
+ public Object getInvocationArgument(int callNum, int argNum)
+ {
+ return _args.get(callNum)[argNum];
+ }
+ }
+
+
//----------------------------------------------------------------------------
// Test Cases
//----------------------------------------------------------------------------
@@ -62,114 +136,212 @@
public void testSingleElement() throws Exception
{
ElementNode node = element("foo");
- assertEquals("<foo/>", node.toString());
Document dom = node.toDOM();
assertRootElement(dom, null, "foo", 0);
+
+ MockContentHandler handler = new MockContentHandler();
+ node.toSAX(handler.getHandler());
+ handler.assertInvocationSequence("startElement", "endElement");
+ handler.assertInvocation(0, "startElement", null, "foo", "foo");
+
+ assertEquals("<foo/>", node.toString());
}
- public void testNamespacedSingleElement() throws Exception
+ public void testSingleElementDefaultNamespace() throws Exception
{
ElementNode node = element("foo", "bar");
+
+ Document dom = node.toDOM();
+ assertRootElement(dom, "foo", "bar", 0);
+
+ MockContentHandler handler = new MockContentHandler();
+ node.toSAX(handler.getHandler());
+ handler.assertInvocationSequence("startElement", "endElement");
+ handler.assertInvocation(0, "startElement", "foo", "bar", "bar");
+
assertEquals("<bar xmlns=\"foo\"/>", node.toString());
+ }
+
+ public void testSingleElementQualifiedNamespace() throws Exception
+ {
+ ElementNode node = element("foo", "bar:baz");
+
Document dom = node.toDOM();
- assertRootElement(dom, "foo", "bar", 0); }
+ assertRootElement(dom, "foo", "bar:baz", 0);
+ MockContentHandler handler = new MockContentHandler();
+ node.toSAX(handler.getHandler());
+ handler.assertInvocationSequence("startElement", "endElement");
+ handler.assertInvocation(0, "startElement", "foo", "baz", "bar:baz");
+ assertEquals("<bar:baz xmlns:bar=\"foo\"/>", node.toString());
+ }
+
+
public void testNestedElement() throws Exception
{
ElementNode node = element("foo", element("bar"));
- assertEquals("<foo><bar/></foo>", node.toString());
Document dom = node.toDOM();
assertRootElement(dom, null, "foo", 1);
assertElement(dom, "/foo/bar", null, "bar", 0);
+
+ MockContentHandler handler = new MockContentHandler();
+ node.toSAX(handler.getHandler());
+ handler.assertInvocationSequence("startElement",
+ "startElement", "endElement",
+ "endElement");
+ handler.assertInvocation(0, "startElement", null, "foo", "foo");
+ handler.assertInvocation(1, "startElement", null, "bar", "bar");
+
+ assertEquals("<foo><bar/></foo>", node.toString());
}
public void testAttribute() throws Exception
{
- Document dom = element("foo",
+ ElementNode node = element("foo",
attribute("argle", "bargle", "wargle"),
- attribute("bar", "baz"))
- .toDOM();
+ attribute("bar", "baz"));
+ Document dom = node.toDOM();
Element root = dom.getDocumentElement();
assertEquals("wargle", root.getAttributeNS("argle", "bargle"));
assertEquals("baz", root.getAttribute("bar"));
+
+ MockContentHandler handler = new MockContentHandler();
+ node.toSAX(handler.getHandler());
+ handler.assertInvocationSequence("startElement", "endElement");
+ handler.assertInvocation(0, "startElement", null, "foo", "foo");
+
+ Attributes attrs = (Attributes)handler.getInvocationArgument(0, 3);
+ assertEquals(2, attrs.getLength());
}
public void testTextElement() throws Exception
{
- Document dom = element("foo", text("bar"))
- .toDOM();
+ ElementNode node = element("foo", text("bar"));
+ Document dom = node.toDOM();
Element root = dom.getDocumentElement();
assertEquals("bar", DomUtil.getText(root));
+
+ MockContentHandler handler = new MockContentHandler();
+ node.toSAX(handler.getHandler());
+ handler.assertInvocationSequence("startElement",
+ "characters",
+ "endElement");
+ handler.assertInvocation(0, "startElement", null, "foo", "foo");
+ handler.assertInvocation(1, "characters", "bar", 0, 3);
+
+ assertEquals("<foo>bar</foo>", node.toString());
}
public void testConsecutiveTextElements() throws Exception
{
- Document dom = element("foo", text("bar"), text("baz"))
- .toDOM();
+ ElementNode node = element("foo", text("bar"), text("baz"));
+ Document dom = node.toDOM();
Element root = dom.getDocumentElement();
assertEquals("barbaz", DomUtil.getText(root));
+
+ MockContentHandler handler = new MockContentHandler();
+ node.toSAX(handler.getHandler());
+ handler.assertInvocationSequence("startElement",
+ "characters", "characters",
+ "endElement");
+ handler.assertInvocation(0, "startElement", null, "foo", "foo");
+ handler.assertInvocation(1, "characters", "bar", 0, 3);
+ handler.assertInvocation(2, "characters", "baz", 0, 3);
+
+ assertEquals("<foo>barbaz</foo>", node.toString());
}
public void testComment() throws Exception
{
- Document dom = element("foo", comment("bar"))
- .toDOM();
+ ElementNode node = element("foo", comment("bar"));
+ Document dom = node.toDOM();
Element root = dom.getDocumentElement();
assertEquals(1, root.getChildNodes().getLength());
-
Comment child = (Comment)root.getChildNodes().item(0);
assertEquals("bar", child.getNodeValue());
+
+ // note: ContentHandler knows nothing of comments
+ MockContentHandler handler = new MockContentHandler();
+ node.toSAX(handler.getHandler());
+ handler.assertInvocationSequence("startElement", "endElement");
+ handler.assertInvocation(0, "startElement", null, "foo", "foo");
+
+
+// assertEquals("<foo><!--bar--></foo>", node.toString());
}
+ public void testPI() throws Exception
+ {
+ ElementNode node = element("foo", processingInstruction("argle", "bargle"));
+
+ Document dom = node.toDOM();
+ Element root = dom.getDocumentElement();
+ assertEquals(1, root.getChildNodes().getLength());
+ ProcessingInstruction child = (ProcessingInstruction)root.getChildNodes().item(0);
+ assertEquals("argle", child.getTarget());
+ assertEquals("bargle", child.getData());
+
+ MockContentHandler handler = new MockContentHandler();
+ node.toSAX(handler.getHandler());
+ handler.assertInvocationSequence(
+ "startElement",
+ "processingInstruction",
+ "endElement");
+ handler.assertInvocation(1, "processingInstruction", "argle", "bargle");
+
+ assertEquals("<foo><?argle bargle?></foo>", node.toString());
+ }
+
+
public void testAddChild() throws Exception
{
ElementNode root = element("foo");
assertSame(root, root.addChild(element("bar")));
- Element eRoot = root.toDOM().getDocumentElement();
- assertEquals("foo", eRoot.getNodeName());
- assertEquals(1, eRoot.getChildNodes().getLength());
- assertEquals("bar", eRoot.getChildNodes().item(0).getNodeName());
- }
+ Document dom = root.toDOM();
+ assertRootElement(dom, null, "foo", 1);
+ MockContentHandler handler = new MockContentHandler();
+ root.toSAX(handler.getHandler());
+ handler.assertInvocationSequence("startElement",
+ "startElement", "endElement",
+ "endElement");
+ handler.assertInvocation(0, "startElement", null, "foo", "foo");
+ handler.assertInvocation(1, "startElement", null, "bar", "bar");
- public void testToString() throws Exception
- {
- String s = element("foo",
- attribute("argle", "bar&gle"),
- element("bar", text("baz")))
- .toString();
- assertEquals("<foo argle=\"bar&gle\"><bar>baz</bar></foo>", s);
+ assertEquals("<foo><bar/></foo>", root.toString());
}
public void testToStringIndented() throws Exception
{
- String s = element("foo", element("bar", text("baz")))
- .toString(3);
+ ElementNode root = element("foo", element("bar", text("baz")));
+
+ String s = root.toString(3);
assertMultiline("<foo>\n <bar>baz</bar>\n</foo>\n", s);
}
public void testToStream() throws Exception
{
+ ElementNode root = element("foo", element("b\u00e2r", text("baz")));
+
ByteArrayOutputStream out = new ByteArrayOutputStream();
- element("foo", element("b\u00e2r", text("baz")))
- .toStream(out);
+ root.toStream(out);
String s = new String(out.toByteArray(), "UTF-8");
assertEquals("<foo><b\u00e2r>baz</b\u00e2r></foo>", s);
@@ -178,9 +350,10 @@
public void testToStreamWithPrologue() throws Exception
{
+ ElementNode root = element("f\u00f6o", element("bar", text("baz")));
+
ByteArrayOutputStream out = new ByteArrayOutputStream();
- element("f\u00f6o", element("bar", text("baz")))
- .toStream(out, "ISO-8859-1");
+ root.toStream(out, "ISO-8859-1");
byte[] b = out.toByteArray();
assertEquals(0xF6, b[b.length-3] & 0xFF);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-04-25 13:59:46
|
Revision: 78
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=78&view=rev
Author: kdgregory
Date: 2009-04-25 13:59:44 +0000 (Sat, 25 Apr 2009)
Log Message:
-----------
refactor tests
Modified Paths:
--------------
trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java
Modified: trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java 2009-04-25 13:17:38 UTC (rev 77)
+++ trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java 2009-04-25 13:59:44 UTC (rev 78)
@@ -16,6 +16,10 @@
import java.io.ByteArrayOutputStream;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -28,44 +32,60 @@
public class TestXmlBuilder
extends AbstractTestCase
{
+//----------------------------------------------------------------------------
+// Support Code
+//----------------------------------------------------------------------------
+
+ private void assertRootElement(Document dom, String nsUri, String name, int childCount)
+ throws Exception
+ {
+ assertElement(dom, "/*[1]", nsUri, name, childCount);
+ }
+
+
+ private void assertElement(Document dom, String path, String nsUri, String name, int childCount)
+ throws Exception
+ {
+ XPath xpath = XPathFactory.newInstance().newXPath();
+ Element elem = (Element)xpath.evaluate(path, dom, XPathConstants.NODE);
+ assertNotNull(elem);
+ assertEquals(nsUri, elem.getNamespaceURI());
+ assertEquals(name, elem.getNodeName());
+ assertEquals(childCount, elem.getChildNodes().getLength());
+ }
+
+
+//----------------------------------------------------------------------------
+// Test Cases
+//----------------------------------------------------------------------------
+
public void testSingleElement() throws Exception
{
- Document dom = element("foo")
- .toDOM();
+ ElementNode node = element("foo");
+ assertEquals("<foo/>", node.toString());
- Element root = dom.getDocumentElement();
- assertNull(root.getNamespaceURI());
- assertEquals("foo", root.getNodeName());
- assertEquals(0, root.getChildNodes().getLength());
+ Document dom = node.toDOM();
+ assertRootElement(dom, null, "foo", 0);
}
public void testNamespacedSingleElement() throws Exception
{
- Document dom = element("foo", "bar")
- .toDOM();
+ ElementNode node = element("foo", "bar");
+ assertEquals("<bar xmlns=\"foo\"/>", node.toString());
- Element root = dom.getDocumentElement();
- assertEquals("foo", root.getNamespaceURI());
- assertEquals("bar", root.getNodeName());
- assertEquals(0, root.getChildNodes().getLength());
- }
+ Document dom = node.toDOM();
+ assertRootElement(dom, "foo", "bar", 0); }
public void testNestedElement() throws Exception
{
- Document dom = element("foo", element("bar"))
- .toDOM();
+ ElementNode node = element("foo", element("bar"));
+ assertEquals("<foo><bar/></foo>", node.toString());
- Element root = dom.getDocumentElement();
- assertNull(root.getNamespaceURI());
- assertEquals("foo", root.getNodeName());
- assertEquals(1, root.getChildNodes().getLength());
-
- Element child = (Element)root.getChildNodes().item(0);
- assertNull(child.getNamespaceURI());
- assertEquals("bar", child.getNodeName());
- assertEquals(0, child.getChildNodes().getLength());
+ Document dom = node.toDOM();
+ assertRootElement(dom, null, "foo", 1);
+ assertElement(dom, "/foo/bar", null, "bar", 0);
}
@@ -129,9 +149,11 @@
public void testToString() throws Exception
{
- String s = element("foo", element("bar", text("baz")))
+ String s = element("foo",
+ attribute("argle", "bar&gle"),
+ element("bar", text("baz")))
.toString();
- assertEquals("<foo><bar>baz</bar></foo>", s);
+ assertEquals("<foo argle=\"bar&gle\"><bar>baz</bar></foo>", s);
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-04-25 13:17:39
|
Revision: 77
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=77&view=rev
Author: kdgregory
Date: 2009-04-25 13:17:38 +0000 (Sat, 25 Apr 2009)
Log Message:
-----------
Add "internal" package
Remove dependency on Jakarta Commons lang
Modified Paths:
--------------
trunk/pom.xml
trunk/src/main/java/net/sf/practicalxml/DomUtil.java
trunk/src/main/java/net/sf/practicalxml/XmlUtil.java
Added Paths:
-----------
trunk/src/main/java/net/sf/practicalxml/internal/
trunk/src/main/java/net/sf/practicalxml/internal/StringUtils.java
trunk/src/main/java/net/sf/practicalxml/internal/package.html
trunk/src/test/java/net/sf/practicalxml/internal/
trunk/src/test/java/net/sf/practicalxml/internal/TestStringUtils.java
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2009-04-25 12:24:37 UTC (rev 76)
+++ trunk/pom.xml 2009-04-25 13:17:38 UTC (rev 77)
@@ -122,11 +122,6 @@
<dependencies>
<dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.3</version>
- </dependency>
- <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
Modified: trunk/src/main/java/net/sf/practicalxml/DomUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/DomUtil.java 2009-04-25 12:24:37 UTC (rev 76)
+++ trunk/src/main/java/net/sf/practicalxml/DomUtil.java 2009-04-25 13:17:38 UTC (rev 77)
@@ -27,11 +27,10 @@
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
+import net.sf.practicalxml.internal.StringUtils;
import net.sf.practicalxml.xpath.NamespaceResolver;
-import org.apache.commons.lang.StringUtils;
-
/**
* A collection of static utility methods for working with DOM trees.
* Most of these are usability workarounds for the <code>org.w3c.dom</code>
Modified: trunk/src/main/java/net/sf/practicalxml/XmlUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/XmlUtil.java 2009-04-25 12:24:37 UTC (rev 76)
+++ trunk/src/main/java/net/sf/practicalxml/XmlUtil.java 2009-04-25 13:17:38 UTC (rev 77)
@@ -21,7 +21,9 @@
import java.util.GregorianCalendar;
import java.util.TimeZone;
+import net.sf.practicalxml.internal.StringUtils;
+
/**
* A collection of static methods for manipulating XML as text.
*/
@@ -399,11 +401,9 @@
// caller has checked &#, so skip them
curPos += 2;
- boolean isHex = false;
int multiplier = 10;
if (s.charAt(curPos) == 'x')
{
- isHex = true;
multiplier = 16;
curPos++;
}
@@ -415,7 +415,7 @@
char c = s.charAt(curPos + ii);
if (c == ';')
break;
- int cVal = convertDigit(c, isHex);
+ int cVal = StringUtils.parseDigit(c, multiplier);
if (cVal < 0)
return '\0';
value = value * multiplier + cVal;
@@ -426,22 +426,4 @@
return (char)value;
}
-
-
- // FIXME - refactor this into a common method
- /**
- * Verifies that the passed character is a digit, and converts it to its
- * numeric value if yes. Returns -1 if not a legal digit.
- */
- private static int convertDigit(char c, boolean allowHex)
- {
- if ((c >= '0') && (c <= '9'))
- return c - '0';
- if (allowHex && (c >= 'a') && (c <= 'f'))
- return c - 'a' + 10;
- if (allowHex && (c >= 'A') && (c <= 'F'))
- return c - 'A' + 10;
- return -1;
- }
-
}
Added: trunk/src/main/java/net/sf/practicalxml/internal/StringUtils.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/internal/StringUtils.java (rev 0)
+++ trunk/src/main/java/net/sf/practicalxml/internal/StringUtils.java 2009-04-25 13:17:38 UTC (rev 77)
@@ -0,0 +1,108 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.internal;
+
+
+/**
+ * Static methods for working with strings and characters. This class exists
+ * primarily to break dependency on Jakarta Commons.
+ */
+public class StringUtils
+{
+ /**
+ * Returns true if the passed string is null or zero-length; false
+ * otherwise (including a string containing only whitespace). This
+ * is a replacement for the Jakarta Commons method with the same
+ * name.
+ */
+ public static boolean isEmpty(String s)
+ {
+ return (s == null) || (s.length() == 0);
+ }
+
+
+ /**
+ * Returns true if the passed string is null, zero-length, or contains
+ * only whitespace characters as defined by Character.isWhitespace();
+ * false otherwise. This is a replacement for the Jakarta Commons method
+ * with the same name.
+ */
+ public static boolean isBlank(String s)
+ {
+ if ((s == null) || (s.length() == 0))
+ return true;
+
+ for (int ii = 0 ; ii < s.length() ; ii++)
+ {
+ if (!Character.isWhitespace(s.charAt(ii)))
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Trims all whitespace characters (as defined by Character.isWhitespace())
+ * from both ends of the string, returning an empty string if there's
+ * nothing left. Will also return an empty string if passed null. This is a
+ * replacement for the Jakarta Commons method with the same name.
+ */
+ public static String trimToEmpty(String s)
+ {
+ if ((s == null) || (s.length() == 0))
+ return "";
+
+ int i0 = 0;
+ int i1 = s.length() - 1;
+ while (i0 <= i1)
+ {
+ if (Character.isWhitespace(s.charAt(i0)))
+ i0++;
+ else if (Character.isWhitespace(s.charAt(i1)))
+ i1--;
+ else
+ return s.substring(i0, i1 + 1);
+ }
+
+ return "";
+ }
+
+
+ /**
+ * Parses the passed character as a digit in the specified base,
+ * returning its value. Bases > 10 are represented by ASCII letters
+ * in the range A to Z (or a to z). Base 36 is the largest supported.
+ *
+ * @return The value, or -1 if the character is not a valid digit
+ * in the specified base (this method will typically be used
+ * in a loop, so no good reason to force exception checking).
+ */
+ public static int parseDigit(char c, int base)
+ {
+ int value = -1;
+ if ((c >= '0') && (c <= '9'))
+ value = c - '0';
+ else if ((c >= 'a') && (c <= 'z'))
+ value = c - 'a' + 10;
+ else if ((c >= 'A') && (c <= 'Z'))
+ value = c - 'A' + 10;
+
+ if (value >= base)
+ value = -1;
+ return value;
+ }
+
+}
Added: trunk/src/main/java/net/sf/practicalxml/internal/package.html
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/internal/package.html (rev 0)
+++ trunk/src/main/java/net/sf/practicalxml/internal/package.html 2009-04-25 13:17:38 UTC (rev 77)
@@ -0,0 +1,4 @@
+This package contains classes used internally by the PracticalXML library.
+Applications should not rely on the API of these classes, or indeed of their
+continued existence. In most cases, there's a better alternative in a third-
+party library.
\ No newline at end of file
Added: trunk/src/test/java/net/sf/practicalxml/internal/TestStringUtils.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/internal/TestStringUtils.java (rev 0)
+++ trunk/src/test/java/net/sf/practicalxml/internal/TestStringUtils.java 2009-04-25 13:17:38 UTC (rev 77)
@@ -0,0 +1,77 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.internal;
+
+import junit.framework.TestCase;
+
+
+public class TestStringUtils extends TestCase
+{
+ public void testIsEmpty() throws Exception
+ {
+ assertTrue(StringUtils.isEmpty(null));
+ assertTrue(StringUtils.isEmpty(""));
+
+ assertFalse(StringUtils.isEmpty("A"));
+ assertFalse(StringUtils.isEmpty(" "));
+ }
+
+
+ public void testIsBlank() throws Exception
+ {
+ assertTrue(StringUtils.isBlank(null));
+ assertTrue(StringUtils.isBlank(""));
+ assertTrue(StringUtils.isBlank(" "));
+ assertTrue(StringUtils.isBlank(" \n "));
+
+ assertFalse(StringUtils.isBlank("A"));
+ assertFalse(StringUtils.isBlank(" A "));
+ assertFalse(StringUtils.isBlank("\u00A0"));
+ }
+
+
+ public void testTrimToEmpty() throws Exception
+ {
+ assertEquals("", StringUtils.trimToEmpty(null));
+ assertEquals("", StringUtils.trimToEmpty(""));
+ assertEquals("", StringUtils.trimToEmpty(" \n \t "));
+
+ assertEquals("A", StringUtils.trimToEmpty(" A\n "));
+ assertEquals("AB", StringUtils.trimToEmpty(" AB\n "));
+ assertEquals("\u00A0", StringUtils.trimToEmpty("\u00A0"));
+ }
+
+
+ public void testParseDigit() throws Exception
+ {
+ assertEquals(0, StringUtils.parseDigit('0', 10));
+ assertEquals(9, StringUtils.parseDigit('9', 10));
+ assertEquals(-1, StringUtils.parseDigit('A', 10));
+
+ assertEquals(0, StringUtils.parseDigit('0', 16));
+ assertEquals(9, StringUtils.parseDigit('9', 16));
+ assertEquals(10, StringUtils.parseDigit('A', 16));
+ assertEquals(15, StringUtils.parseDigit('F', 16));
+ assertEquals(-1, StringUtils.parseDigit('G', 16));
+ assertEquals(10, StringUtils.parseDigit('a', 16));
+ assertEquals(15, StringUtils.parseDigit('f', 16));
+ assertEquals(-1, StringUtils.parseDigit('g', 16));
+
+ assertEquals(35, StringUtils.parseDigit('Z', 36));
+ assertEquals(35, StringUtils.parseDigit('z', 36));
+
+ assertEquals(-1, StringUtils.parseDigit('!', 100));
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-04-25 12:24:50
|
Revision: 76
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=76&view=rev
Author: kdgregory
Date: 2009-04-25 12:24:37 +0000 (Sat, 25 Apr 2009)
Log Message:
-----------
Add XmlUtil.escape, XmlUtil.unescape
Modified Paths:
--------------
trunk/pom.xml
trunk/src/main/java/net/sf/practicalxml/XmlUtil.java
trunk/src/test/java/net/sf/practicalxml/TestXmlUtil.java
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2009-01-14 14:14:44 UTC (rev 75)
+++ trunk/pom.xml 2009-04-25 12:24:37 UTC (rev 76)
@@ -5,7 +5,7 @@
<groupId>net.sf.practicalxml</groupId>
<artifactId>practicalxml</artifactId>
<packaging>jar</packaging>
- <version>1.0.0</version>
+ <version>1.0.1</version>
<name>practicalxml</name>
<url>http://sourceforge.net/projects/practicalxml/</url>
Modified: trunk/src/main/java/net/sf/practicalxml/XmlUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/XmlUtil.java 2009-01-14 14:14:44 UTC (rev 75)
+++ trunk/src/main/java/net/sf/practicalxml/XmlUtil.java 2009-04-25 12:24:37 UTC (rev 76)
@@ -122,6 +122,95 @@
}
+ /**
+ * Escapes the passed string, converting the five reserved XML characters
+ * into their entities: &amp;, &lt;, &gt;, &apos;, and
+ * &quot;. If the string does not contain any of these characters, it
+ * will be returned unchanged. If passed <code>null</code>, returns an
+ * empty string.
+ * <p>
+ * Yes, this method is available elsewhere, eg Jakarta Commons. I'm trying
+ * to minimize external dependencies from this library, so am reinventing
+ * a few small wheels (but they're round!).
+ */
+ public static String escape(String s)
+ {
+ if (s == null)
+ return "";
+
+ StringBuilder buf = new StringBuilder(s.length());
+ boolean wasEscaped = false;
+
+ for (int ii = 0 ; ii < s.length() ; ii++)
+ {
+ char c = s.charAt(ii);
+ switch (c)
+ {
+ case '&' :
+ buf.append("&");
+ wasEscaped = true;
+ break;
+ case '<' :
+ buf.append("<");
+ wasEscaped = true;
+ break;
+ case '>' :
+ buf.append(">");
+ wasEscaped = true;
+ break;
+ case '\'' :
+ buf.append("'");
+ wasEscaped = true;
+ break;
+ case '"' :
+ buf.append(""");
+ wasEscaped = true;
+ break;
+ default :
+ buf.append(c);
+ }
+ }
+
+ return wasEscaped ? buf.toString() : s;
+ }
+
+
+ /**
+ * Unescapes the passed string, converting the five XML entities
+ * (&amp;, &lt;, &gt;, &apos;, and &quot;) into
+ * their correspinding characters. Also converts any numeric entities
+ * into their characters. If the string does not contain any convertable
+ * entities, it will be returned unchanged. If passed <code>null</code>,
+ * returns an empty string.
+ * <p>
+ * Yes, this method is available elsewhere, eg Jakarta Commons.
+ */
+ public static String unescape(String s)
+ {
+ if (s == null)
+ return "";
+
+ StringBuilder buf = new StringBuilder(s.length() + 20);
+ boolean wasEscaped = false;
+
+ for (int ii = 0 ; ii < s.length() ; ii++)
+ {
+ char c = s.charAt(ii);
+ switch (c)
+ {
+ case '&' :
+ ii = unescapeHelper(s, ii, buf);
+ wasEscaped = true;
+ break;
+ default :
+ buf.append(c);
+ }
+ }
+
+ return wasEscaped ? buf.toString() : s;
+ }
+
+
//----------------------------------------------------------------------------
// Internals
//----------------------------------------------------------------------------
@@ -234,4 +323,125 @@
: "GMT";
cal.setTimeZone(TimeZone.getTimeZone(tz));
}
+
+
+ /**
+ * Attempts to recognize an entity in the passed string, appending the
+ * corresponding character to the passed buffer. If unable to recognize
+ * an entity, appends the current character (an ampersand) to the buffer.
+ * Returns the updated string index (position of the trailing semi-colon).
+ */
+ private static int unescapeHelper(String s, int curPos, StringBuilder buf)
+ {
+ // the case of a malformed entity at the end of the string should be
+ // all but nonexistent in the real world, so rather than clutter the
+ // code with index tests, I'll just catch the exception
+ try
+ {
+ if (s.startsWith("&", curPos))
+ {
+ buf.append("&");
+ return curPos + 4;
+ }
+ else if (s.startsWith("'", curPos))
+ {
+ buf.append("'");
+ return curPos + 5;
+ }
+ else if (s.startsWith(""", curPos))
+ {
+ buf.append('"');
+ return curPos + 5;
+ }
+ else if (s.startsWith("<", curPos))
+ {
+ buf.append("<");
+ return curPos + 3;
+ }
+ else if (s.startsWith(">", curPos))
+ {
+ buf.append(">");
+ return curPos + 3;
+ }
+ else if (s.startsWith("&#", curPos))
+ {
+ char c = numericEntityHelper(s, curPos);
+ if (c != '\0')
+ {
+ buf.append(c);
+ return s.indexOf(';', curPos);
+ }
+ }
+ }
+ catch (StringIndexOutOfBoundsException ignored)
+ {
+ // fall through to default handler
+ }
+
+ // it's not an entity that we know how to process, so just copy the
+ // ampersand and let the rest of the string process
+ buf.append('&');
+ return curPos;
+ }
+
+
+ /**
+ * Attempts to decode a numeric character entity starting at the current
+ * position within the string. If able, returns the corresponding character.
+ * If unable, returns NUL (which is disallowed by both XML 1.0 and XML 1.1).
+ * <p>
+ * Limited to
+ */
+ private static char numericEntityHelper(String s, int curPos)
+ {
+ int value = 0;
+
+ // caller has checked &#, so skip them
+ curPos += 2;
+
+ boolean isHex = false;
+ int multiplier = 10;
+ if (s.charAt(curPos) == 'x')
+ {
+ isHex = true;
+ multiplier = 16;
+ curPos++;
+ }
+
+ // XML is limited to Unicode plane 0, so 4 hex or 5 decimal digits
+ // ... don't index through entire string looking for semi-colon
+ for (int ii = 0 ; ii < 6 ; ii++)
+ {
+ char c = s.charAt(curPos + ii);
+ if (c == ';')
+ break;
+ int cVal = convertDigit(c, isHex);
+ if (cVal < 0)
+ return '\0';
+ value = value * multiplier + cVal;
+ }
+
+ if (value > 65535)
+ return '\0';
+
+ return (char)value;
+ }
+
+
+ // FIXME - refactor this into a common method
+ /**
+ * Verifies that the passed character is a digit, and converts it to its
+ * numeric value if yes. Returns -1 if not a legal digit.
+ */
+ private static int convertDigit(char c, boolean allowHex)
+ {
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+ if (allowHex && (c >= 'a') && (c <= 'f'))
+ return c - 'a' + 10;
+ if (allowHex && (c >= 'A') && (c <= 'F'))
+ return c - 'A' + 10;
+ return -1;
+ }
+
}
Modified: trunk/src/test/java/net/sf/practicalxml/TestXmlUtil.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestXmlUtil.java 2009-01-14 14:14:44 UTC (rev 75)
+++ trunk/src/test/java/net/sf/practicalxml/TestXmlUtil.java 2009-04-25 12:24:37 UTC (rev 76)
@@ -75,4 +75,60 @@
assertEquals(expected.getTime(), XmlUtil.parseXsdDatetime("2004-10-28T09:10:11.123"));
assertEquals(expected.getTime(), XmlUtil.parseXsdDatetime("2004-10-28T04:10:11.123-05:00"));
}
+
+
+ public void testEscape() throws Exception
+ {
+ assertEquals("", XmlUtil.escape(null));
+ assertEquals("", XmlUtil.escape(""));
+
+ String s1 = new String("this has nothing to escape");
+ assertSame(s1, XmlUtil.escape(s1));
+
+ assertEquals("this & <string> does "'",
+ XmlUtil.escape("this & <string> does \"'"));
+ }
+
+
+ public void testUnescape() throws Exception
+ {
+ assertEquals("", XmlUtil.unescape(null));
+ assertEquals("", XmlUtil.unescape(""));
+
+ String s1 = new String("this has nothing to escape");
+ assertSame(s1, XmlUtil.unescape(s1));
+
+ assertEquals("this string'\"does<&>",
+ XmlUtil.unescape("this string'"does<&>"));
+
+ assertEquals("this is an &unknown; entity",
+ XmlUtil.unescape("this is an &unknown; entity"));
+ }
+
+
+ public void testUnescapeWithInvalidNumericEntity() throws Exception
+ {
+ assertEquals("𘚟",
+ XmlUtil.unescape("𘚟"));
+ assertEquals("𒍅",
+ XmlUtil.unescape("𒍅"));
+ assertEquals("cAA;",
+ XmlUtil.unescape("cAA;"));
+
+ assertEquals("&#;",
+ XmlUtil.unescape("&#;"));
+
+ assertEquals("&#this is not really an entity",
+ XmlUtil.unescape("&#this is not really an entity"));
+ }
+
+
+ public void testUnescapeAtEndOfString() throws Exception
+ {
+ assertEquals("&",
+ XmlUtil.unescape("&"));
+ assertEquals("&am",
+ XmlUtil.unescape("&am"));
+ }
+
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-01-14 14:14:55
|
Revision: 75
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=75&view=rev
Author: kdgregory
Date: 2009-01-14 14:14:44 +0000 (Wed, 14 Jan 2009)
Log Message:
-----------
add license info to POM
Modified Paths:
--------------
trunk/pom.xml
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2009-01-14 13:44:22 UTC (rev 74)
+++ trunk/pom.xml 2009-01-14 14:14:44 UTC (rev 75)
@@ -43,6 +43,14 @@
</developer>
</developers>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+
<scm>
<connection>scm:svn:https://practicalxml.svn.sourceforge.net/svnroot/practicalxml</connection>
<developerConnection>scm:svn:https://practicalxml.svn.sourceforge.net/svnroot/practicalxml</developerConnection>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-01-14 13:44:35
|
Revision: 74
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=74&view=rev
Author: kdgregory
Date: 2009-01-14 13:44:22 +0000 (Wed, 14 Jan 2009)
Log Message:
-----------
tag release 1.0.0
Added Paths:
-----------
tags/rel-1.0/
tags/rel-1.0/pom.xml
Removed Paths:
-------------
tags/rel-1.0/pom.xml
Deleted: tags/rel-1.0/pom.xml
===================================================================
--- trunk/pom.xml 2009-01-14 13:37:46 UTC (rev 72)
+++ tags/rel-1.0/pom.xml 2009-01-14 13:44:22 UTC (rev 74)
@@ -1,127 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <groupId>net.sf.practicalxml</groupId>
- <artifactId>practicalxml</artifactId>
- <packaging>jar</packaging>
- <version>1.0-SNAPSHOT</version>
- <name>practicalxml</name>
- <url>http://sourceforge.net/projects/practicalxml/</url>
-
- <description>
- A collection of utility classes for working with the XML support built-in
- to the JDK.
- </description>
-
- <mailingLists>
- <mailingList>
- <name>practicalxml-commits</name>
- <subscribe>http://lists.sourceforge.net/mailman/listinfo/practicalxml-commits</subscribe>
- <unsubscribe>http://lists.sourceforge.net/mailman/listinfo/practicalxml-commits</unsubscribe>
- <archive>http://sourceforge.net/mailarchive/forum.php?forum_name=practicalxml-commits</archive>
- </mailingList>
- </mailingLists>
-
- <developers>
- <developer>
- <id>kdgregory</id>
- <name>Keith D Gregory</name>
- <url>http://www.kdgregory.com</url>
- </developer>
- <developer>
- <id>ebernstein</id>
- <name>Eric Bernstein</name>
- </developer>
- <developer>
- <id>kmudrick</id>
- <name>Kevin Mudrick</name>
- </developer>
- <developer>
- <id>salewski</id>
- <name>Alan D. Salewski</name>
- </developer>
- </developers>
-
- <scm>
- <connection>scm:svn:https://practicalxml.svn.sourceforge.net/svnroot/practicalxml</connection>
- <developerConnection>scm:svn:https://practicalxml.svn.sourceforge.net/svnroot/practicalxml</developerConnection>
- <url>http://practicalxml.svn.sourceforge.net/viewvc/practicalxml/</url>
- </scm>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.5</source>
- <target>1.5</target>
- <compilerArgument>-g</compilerArgument>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
- <reporting>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-project-info-reports-plugin</artifactId>
- <version>2.0.1</version>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-javadoc-plugin</artifactId>
- <configuration>
- <bottom>
- <a href="http://sourceforge.net/">
- <img src="http://sflogo.sourceforge.net/sflogo.php?group_id=234884&type=3">
- </a>
- </bottom>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-report-plugin</artifactId>
- <version>2.4.2</version>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-changelog-plugin</artifactId>
- </plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>cobertura-maven-plugin</artifactId>
- <configuration>
- <instrumentation>
- <excludes>
- <exclude>**/Test*.class</exclude>
- <exclude>**/AbstractTestCase.class</exclude>
- </excludes>
- </instrumentation>
- <executions>
- <execution>
- <goals>
- <goal>clean</goal>
- </goals>
- </execution>
- </executions>
- </configuration>
- </plugin>
- </plugins>
- </reporting>
-
- <dependencies>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.3</version>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.2</version>
- </dependency>
- </dependencies>
-</project>
Copied: tags/rel-1.0/pom.xml (from rev 73, trunk/pom.xml)
===================================================================
--- tags/rel-1.0/pom.xml (rev 0)
+++ tags/rel-1.0/pom.xml 2009-01-14 13:44:22 UTC (rev 74)
@@ -0,0 +1,127 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>net.sf.practicalxml</groupId>
+ <artifactId>practicalxml</artifactId>
+ <packaging>jar</packaging>
+ <version>1.0.0</version>
+ <name>practicalxml</name>
+ <url>http://sourceforge.net/projects/practicalxml/</url>
+
+ <description>
+ A collection of utility classes for working with the XML support built-in
+ to the JDK.
+ </description>
+
+ <mailingLists>
+ <mailingList>
+ <name>practicalxml-commits</name>
+ <subscribe>http://lists.sourceforge.net/mailman/listinfo/practicalxml-commits</subscribe>
+ <unsubscribe>http://lists.sourceforge.net/mailman/listinfo/practicalxml-commits</unsubscribe>
+ <archive>http://sourceforge.net/mailarchive/forum.php?forum_name=practicalxml-commits</archive>
+ </mailingList>
+ </mailingLists>
+
+ <developers>
+ <developer>
+ <id>kdgregory</id>
+ <name>Keith D Gregory</name>
+ <url>http://www.kdgregory.com</url>
+ </developer>
+ <developer>
+ <id>ebernstein</id>
+ <name>Eric Bernstein</name>
+ </developer>
+ <developer>
+ <id>kmudrick</id>
+ <name>Kevin Mudrick</name>
+ </developer>
+ <developer>
+ <id>salewski</id>
+ <name>Alan D. Salewski</name>
+ </developer>
+ </developers>
+
+ <scm>
+ <connection>scm:svn:https://practicalxml.svn.sourceforge.net/svnroot/practicalxml</connection>
+ <developerConnection>scm:svn:https://practicalxml.svn.sourceforge.net/svnroot/practicalxml</developerConnection>
+ <url>http://practicalxml.svn.sourceforge.net/viewvc/practicalxml/</url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ <compilerArgument>-g</compilerArgument>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-project-info-reports-plugin</artifactId>
+ <version>2.0.1</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <bottom>
+ <a href="http://sourceforge.net/">
+ <img src="http://sflogo.sourceforge.net/sflogo.php?group_id=234884&type=3">
+ </a>
+ </bottom>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ <version>2.4.2</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-changelog-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>cobertura-maven-plugin</artifactId>
+ <configuration>
+ <instrumentation>
+ <excludes>
+ <exclude>**/Test*.class</exclude>
+ <exclude>**/AbstractTestCase.class</exclude>
+ </excludes>
+ </instrumentation>
+ <executions>
+ <execution>
+ <goals>
+ <goal>clean</goal>
+ </goals>
+ </execution>
+ </executions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ <dependencies>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.3</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.2</version>
+ </dependency>
+ </dependencies>
+</project>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-01-14 13:42:14
|
Revision: 73
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=73&view=rev
Author: kdgregory
Date: 2009-01-14 13:42:04 +0000 (Wed, 14 Jan 2009)
Log Message:
-----------
update POM for release
Modified Paths:
--------------
trunk/pom.xml
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2009-01-14 13:37:46 UTC (rev 72)
+++ trunk/pom.xml 2009-01-14 13:42:04 UTC (rev 73)
@@ -5,7 +5,7 @@
<groupId>net.sf.practicalxml</groupId>
<artifactId>practicalxml</artifactId>
<packaging>jar</packaging>
- <version>1.0-SNAPSHOT</version>
+ <version>1.0.0</version>
<name>practicalxml</name>
<url>http://sourceforge.net/projects/practicalxml/</url>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-01-14 13:37:51
|
Revision: 72
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=72&view=rev
Author: kdgregory
Date: 2009-01-14 13:37:46 +0000 (Wed, 14 Jan 2009)
Log Message:
-----------
add README
Added Paths:
-----------
trunk/README.txt
Added: trunk/README.txt
===================================================================
--- trunk/README.txt (rev 0)
+++ trunk/README.txt 2009-01-14 13:37:46 UTC (rev 72)
@@ -0,0 +1,48 @@
+Practical XML - Providing What The JDK Doesn't
+
+ This library is designed to be an easy-to-use wrapper around the XML
+ support built-in to the JDK. It is based on the idea that the JDK
+ implementations will live forever and be regularly updated, something
+ that cannot be said about third-party alternatives.
+
+Licensing and Copyright
+
+ This library is released under the Apache 2 license:
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Copyright is retained by the individual maintainers, for the code
+ that they have contributed. In the case of patch submissions from
+ third parties, the patch contributor implicitly assigns copyright
+ to the maintainer who implements the patch.
+
+Release Numbering
+
+ All builds post initial release have a three part revision number:
+ MAJOR.MINOR.PATCH
+
+ MAJOR releases are not required to be backwards compatible with
+ the previous such release. For example, the 1.0.0 release
+ has a different package structure than the 0.9.0 release.
+ It is intended that there will never be a change to the
+ major release number, although "never" is a long time.
+ MINOR releases will happen whenever a maintainer decides that
+ one is needed, typically driven by significant new
+ functionality and a desire to have the release in a central
+ repository. Minor releases preserve backwards compatibility:
+ code written for one minor release will work when linked
+ with another minor release.
+ PATCH releases won't actually get released: the PATCH revision
+ number should be incremented with each checkin, in preference
+ to using a "-SNAPSHOT" of the next minor release. This will
+ lock users into keeping their build scripts and local repository
+ up-to-date, which is a Good Thing.
+
+ Major and minor releases will be tagged in the Subversion repository,
+ using the form "rel-X.Y", where X and Y are the major and minor release
+ numbers. Patch releases may be tagged using the form "rel-X.Y.Z", if the
+ maintainer decides that it's important to rebuild that particular release
+ (although making it a minor release might be a better idea).
+
+ Major and minor releases will be available for download from Sourceforge
+ ( http://sourceforge.net/project/showfiles.php?group_id=234884 ), and also
+ from the Central Maven Repository.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2009-01-02 13:20:13
|
Revision: 71
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=71&view=rev
Author: kdgregory
Date: 2009-01-02 13:19:54 +0000 (Fri, 02 Jan 2009)
Log Message:
-----------
Add license
Modified Paths:
--------------
trunk/src/example/java/net/sf/practicalxml/example/BuilderExample.java
trunk/src/main/java/net/sf/practicalxml/DomUtil.java
trunk/src/main/java/net/sf/practicalxml/OutputUtil.java
trunk/src/main/java/net/sf/practicalxml/ParseUtil.java
trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java
trunk/src/main/java/net/sf/practicalxml/XmlException.java
trunk/src/main/java/net/sf/practicalxml/XmlUtil.java
trunk/src/main/java/net/sf/practicalxml/builder/AttributeNode.java
trunk/src/main/java/net/sf/practicalxml/builder/CommentNode.java
trunk/src/main/java/net/sf/practicalxml/builder/ElementNode.java
trunk/src/main/java/net/sf/practicalxml/builder/Node.java
trunk/src/main/java/net/sf/practicalxml/builder/TextNode.java
trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilder.java
trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilderException.java
trunk/src/main/java/net/sf/practicalxml/junit/DomAsserts.java
trunk/src/main/java/net/sf/practicalxml/util/ErrorHandlerAdapter.java
trunk/src/main/java/net/sf/practicalxml/util/ExceptionErrorHandler.java
trunk/src/main/java/net/sf/practicalxml/util/NodeListIterable.java
trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java
trunk/src/main/java/net/sf/practicalxml/xpath/FunctionResolver.java
trunk/src/main/java/net/sf/practicalxml/xpath/NamespaceResolver.java
trunk/src/main/java/net/sf/practicalxml/xpath/SimpleNamespaceResolver.java
trunk/src/main/java/net/sf/practicalxml/xpath/XPathWrapper.java
trunk/src/main/java/net/sf/practicalxml/xpath/function/Constants.java
trunk/src/main/java/net/sf/practicalxml/xpath/function/Lowercase.java
trunk/src/main/java/net/sf/practicalxml/xpath/function/Uppercase.java
trunk/src/main/java/net/sf/practicalxml/xpath/function/XsiBoolean.java
trunk/src/test/java/net/sf/practicalxml/AbstractTestCase.java
trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java
trunk/src/test/java/net/sf/practicalxml/TestDomUtilGetPath.java
trunk/src/test/java/net/sf/practicalxml/TestOutputUtil.java
trunk/src/test/java/net/sf/practicalxml/TestParseUtil.java
trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java
trunk/src/test/java/net/sf/practicalxml/TestXmlUtil.java
trunk/src/test/java/net/sf/practicalxml/builder/TestXmlBuilder.java
trunk/src/test/java/net/sf/practicalxml/junit/TestDomAsserts.java
trunk/src/test/java/net/sf/practicalxml/util/TestNodeListIterable.java
trunk/src/test/java/net/sf/practicalxml/xpath/TestAbstractFunction.java
trunk/src/test/java/net/sf/practicalxml/xpath/TestFunctionResolver.java
trunk/src/test/java/net/sf/practicalxml/xpath/TestNamespaceResolver.java
trunk/src/test/java/net/sf/practicalxml/xpath/TestSimpleNamespaceResolver.java
trunk/src/test/java/net/sf/practicalxml/xpath/TestXPathWrapper.java
trunk/src/test/java/net/sf/practicalxml/xpath/function/TestLowercase.java
trunk/src/test/java/net/sf/practicalxml/xpath/function/TestUppercase.java
trunk/src/test/java/net/sf/practicalxml/xpath/function/TestXsiBoolean.java
Added Paths:
-----------
trunk/LICENSE.txt
trunk/src/main/resources/
trunk/src/main/resources/LICENSE.txt
Added: trunk/LICENSE.txt
===================================================================
--- trunk/LICENSE.txt (rev 0)
+++ trunk/LICENSE.txt 2009-01-02 13:19:54 UTC (rev 71)
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
Modified: trunk/src/example/java/net/sf/practicalxml/example/BuilderExample.java
===================================================================
--- trunk/src/example/java/net/sf/practicalxml/example/BuilderExample.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/example/java/net/sf/practicalxml/example/BuilderExample.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.example;
import net.sf.practicalxml.builder.ElementNode;
Modified: trunk/src/main/java/net/sf/practicalxml/DomUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/DomUtil.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/DomUtil.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml;
import java.util.ArrayList;
Modified: trunk/src/main/java/net/sf/practicalxml/OutputUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/OutputUtil.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/OutputUtil.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml;
import java.io.IOException;
Modified: trunk/src/main/java/net/sf/practicalxml/ParseUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/ParseUtil.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/ParseUtil.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml;
import java.io.IOException;
@@ -8,15 +22,15 @@
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.validation.Schema;
-import net.sf.practicalxml.util.ExceptionErrorHandler;
-
import org.w3c.dom.Document;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
+import net.sf.practicalxml.util.ExceptionErrorHandler;
+
/**
* A collection of static methods for parsing XML into a DOM, with or without
* validation.
Modified: trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml;
import java.util.Comparator;
Modified: trunk/src/main/java/net/sf/practicalxml/XmlException.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/XmlException.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/XmlException.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml;
Modified: trunk/src/main/java/net/sf/practicalxml/XmlUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/XmlUtil.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/XmlUtil.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml;
import java.text.DateFormat;
Modified: trunk/src/main/java/net/sf/practicalxml/builder/AttributeNode.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/AttributeNode.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/builder/AttributeNode.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.builder;
import org.w3c.dom.Element;
Modified: trunk/src/main/java/net/sf/practicalxml/builder/CommentNode.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/CommentNode.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/builder/CommentNode.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.builder;
import org.w3c.dom.Comment;
Modified: trunk/src/main/java/net/sf/practicalxml/builder/ElementNode.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/ElementNode.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/builder/ElementNode.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.builder;
import java.io.OutputStream;
Modified: trunk/src/main/java/net/sf/practicalxml/builder/Node.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/Node.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/builder/Node.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.builder;
import org.w3c.dom.Element;
Modified: trunk/src/main/java/net/sf/practicalxml/builder/TextNode.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/TextNode.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/builder/TextNode.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.builder;
import org.w3c.dom.Element;
Modified: trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilder.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilder.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilder.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.builder;
Modified: trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilderException.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilderException.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/builder/XmlBuilderException.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.builder;
Modified: trunk/src/main/java/net/sf/practicalxml/junit/DomAsserts.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/junit/DomAsserts.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/junit/DomAsserts.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,17 +1,32 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.junit;
-import static junit.framework.Assert.*;
-
import java.util.List;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
import junit.framework.Assert;
import net.sf.practicalxml.DomUtil;
import net.sf.practicalxml.xpath.XPathWrapper;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
+import static junit.framework.Assert.*;
+
/**
* JUnit assertions for DOM documents. These are defined as static methods,
* so may be statically imported (although in some cases this will clash
Modified: trunk/src/main/java/net/sf/practicalxml/util/ErrorHandlerAdapter.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/util/ErrorHandlerAdapter.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/util/ErrorHandlerAdapter.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.util;
import org.xml.sax.ErrorHandler;
Modified: trunk/src/main/java/net/sf/practicalxml/util/ExceptionErrorHandler.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/util/ExceptionErrorHandler.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/util/ExceptionErrorHandler.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.util;
import java.util.ArrayList;
@@ -3,11 +17,11 @@
import java.util.List;
-import net.sf.practicalxml.XmlException;
-
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
+import net.sf.practicalxml.XmlException;
+
/**
* An error handler that throws <code>XmlException</code> on any error,
Modified: trunk/src/main/java/net/sf/practicalxml/util/NodeListIterable.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/util/NodeListIterable.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/util/NodeListIterable.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.util;
import java.util.Iterator;
Modified: trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.xpath;
import java.util.Collections;
Modified: trunk/src/main/java/net/sf/practicalxml/xpath/FunctionResolver.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/FunctionResolver.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/FunctionResolver.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.xpath;
import java.util.HashMap;
Modified: trunk/src/main/java/net/sf/practicalxml/xpath/NamespaceResolver.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/NamespaceResolver.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/NamespaceResolver.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.xpath;
import java.util.ArrayList;
Modified: trunk/src/main/java/net/sf/practicalxml/xpath/SimpleNamespaceResolver.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/SimpleNamespaceResolver.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/SimpleNamespaceResolver.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.xpath;
import java.util.Arrays;
Modified: trunk/src/main/java/net/sf/practicalxml/xpath/XPathWrapper.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/XPathWrapper.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/XPathWrapper.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.xpath;
import java.util.HashMap;
Modified: trunk/src/main/java/net/sf/practicalxml/xpath/function/Constants.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/function/Constants.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/function/Constants.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.xpath.function;
/**
Modified: trunk/src/main/java/net/sf/practicalxml/xpath/function/Lowercase.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/function/Lowercase.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/function/Lowercase.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.xpath.function;
import org.w3c.dom.Node;
Modified: trunk/src/main/java/net/sf/practicalxml/xpath/function/Uppercase.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/function/Uppercase.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/function/Uppercase.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.xpath.function;
import org.w3c.dom.Node;
Modified: trunk/src/main/java/net/sf/practicalxml/xpath/function/XsiBoolean.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/function/XsiBoolean.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/function/XsiBoolean.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml.xpath.function;
import org.w3c.dom.Node;
@@ -66,4 +80,4 @@
{
return Boolean.FALSE;
}
-}
\ No newline at end of file
+}
Added: trunk/src/main/resources/LICENSE.txt
===================================================================
--- trunk/src/main/resources/LICENSE.txt (rev 0)
+++ trunk/src/main/resources/LICENSE.txt 2009-01-02 13:19:54 UTC (rev 71)
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
Modified: trunk/src/test/java/net/sf/practicalxml/AbstractTestCase.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/AbstractTestCase.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/test/java/net/sf/practicalxml/AbstractTestCase.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml;
import junit.framework.TestCase;
Modified: trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml;
import java.util.List;
Modified: trunk/src/test/java/net/sf/practicalxml/TestDomUtilGetPath.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestDomUtilGetPath.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/test/java/net/sf/practicalxml/TestDomUtilGetPath.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 net.sf.practicalxml;
import javax.xml.namespace.NamespaceContext;
Modified: trunk/src/test/java/net/sf/practicalxml/TestOutputUtil.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestOutputUtil.java 2008-12-30 14:08:10 UTC (rev 70)
+++ trunk/src/test/java/net/sf/practicalxml/TestOutputUtil.java 2009-01-02 13:19:54 UTC (rev 71)
@@ -1,3 +1,17 @@
+// Copyright 2008-2009 severally by the contributors
+//
+// 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 ...
[truncated message content] |
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-30 14:08:12
|
Revision: 70
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=70&view=rev
Author: kdgregory
Date: 2008-12-30 14:08:10 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
XPathWrapper: all forms of evaluate() now take a Node, for consistency with the rest of the world
- refactor evaluation
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/xpath/XPathWrapper.java
trunk/src/test/java/net/sf/practicalxml/xpath/TestXPathWrapper.java
Modified: trunk/src/main/java/net/sf/practicalxml/xpath/XPathWrapper.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/XPathWrapper.java 2008-12-30 14:01:57 UTC (rev 69)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/XPathWrapper.java 2008-12-30 14:08:10 UTC (rev 70)
@@ -1,6 +1,5 @@
package net.sf.practicalxml.xpath;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -13,11 +12,10 @@
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathVariableResolver;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import net.sf.practicalxml.DomUtil;
import net.sf.practicalxml.XmlException;
@@ -142,7 +140,7 @@
*
* @return The wrapper, so that calls may be chained.
*/
- public XPathWrapper bindFunction(AbstractFunction func)
+ public XPathWrapper bindFunction(AbstractFunction<?> func)
{
_functions.addFunction(func);
return this;
@@ -164,7 +162,7 @@
*
* @return The wrapper, so that calls may be chained.
*/
- public XPathWrapper bindFunction(AbstractFunction func, String prefix)
+ public XPathWrapper bindFunction(AbstractFunction<?> func, String prefix)
{
_functions.addFunction(func);
return bindNamespace(prefix, func.getNamespaceUri());
@@ -254,121 +252,44 @@
/**
- * Applies this expression to the root of the specified document,
- * converting the resulting NodeList into a java.util.List for ease
- * in iteration.
+ * Applies this expression to the the specified node, converting the
+ * resulting <code>NodeList</code> into a <code>java.util.List</code>.
*/
- public List<Node> evaluate(Document context)
+ public List<Node> evaluate(Node context)
{
- return evaluate(context.getDocumentElement());
+ return DomUtil.asList(
+ evaluate(context, XPathConstants.NODESET, NodeList.class),
+ Node.class);
}
/**
- * Applies this expression to the specified element, converting the
- * resulting NodeList into a java.util.List for ease in iteration.
- */
- public List<Node> evaluate(Element context)
- {
- compileIfNeeded();
- try
- {
- NodeList result = (NodeList)_compiled.evaluate(context, XPathConstants.NODESET);
- List<Node> ret = new ArrayList<Node>(result.getLength());
- for (int ii = 0 ; ii < result.getLength() ; ii++)
- {
- ret.add(result.item(ii));
- }
- return ret;
- }
- catch (Exception ee)
- {
- throw new XmlException("unable to evaluate: " + _expr, ee);
- }
- }
-
-
- /**
- * Applies this expression to the root of the specified document,
- * requesting the <code>STRING</code> return type.
- */
- public String evaluateAsString(Document context)
- {
- return evaluateAsString(context.getDocumentElement());
- }
-
-
- /**
- * Applies this expression to the specified element, requesting the
+ * Applies this expression to the specified node, requesting the
* <code>STRING</code> return type.
*/
- public String evaluateAsString(Element context)
+ public String evaluateAsString(Node context)
{
- compileIfNeeded();
- try
- {
- return _compiled.evaluate(context);
- }
- catch (Exception ee)
- {
- throw new XmlException("unable to evaluate: " + _expr, ee);
- }
+ return evaluate(context, XPathConstants.STRING, String.class);
}
/**
- * Applies this expression to the root of the specified document,
- * requesting the <code>NUMBER</code> return type.
- */
- public Double evaluateAsNumber(Document context)
- {
- return evaluateAsNumber(context.getDocumentElement());
- }
-
-
- /**
- * Applies this expression to the specified element, requesting the
+ * Applies this expression to the specified node, requesting the
* <code>NUMBER</code> return type.
*/
- public Double evaluateAsNumber(Element context)
+ public Number evaluateAsNumber(Node context)
{
- compileIfNeeded();
- try
- {
- return (Double)_compiled.evaluate(context, XPathConstants.NUMBER);
- }
- catch (Exception ee)
- {
- throw new XmlException("unable to evaluate: " + _expr, ee);
- }
+ return evaluate(context, XPathConstants.NUMBER, Number.class);
}
/**
- * Applies this expression to the root of the specified document,
- * requesting the <code>BOOLEAN</code> return type.
- */
- public Boolean evaluateAsBoolean(Document context)
- {
- return evaluateAsBoolean(context.getDocumentElement());
- }
-
-
- /**
- * Applies this expression to the specified element, requesting the
+ * Applies this expression to the the specified node, requesting the
* <code>BOOLEAN</code> return type.
*/
- public Boolean evaluateAsBoolean(Element context)
+ public Boolean evaluateAsBoolean(Node context)
{
- compileIfNeeded();
- try
- {
- return (Boolean)_compiled.evaluate(context, XPathConstants.BOOLEAN);
- }
- catch (Exception ee)
- {
- throw new XmlException("unable to evaluate: " + _expr, ee);
- }
+ return evaluate(context, XPathConstants.BOOLEAN, Boolean.class);
}
@@ -376,7 +297,6 @@
// Overrides of Object
//----------------------------------------------------------------------------
-
/**
* Two instances are considered equal if they have the same expression,
* namespace mappings, variable mappings, and function mappings. Note
@@ -450,6 +370,24 @@
/**
+ * Compiles and executes the expression in the context of the specified
+ * node, returning the specified result type.
+ */
+ private <T> T evaluate(Node context, QName returnType, Class<T> castTo)
+ {
+ compileIfNeeded();
+ try
+ {
+ return castTo.cast(_compiled.evaluate(context, returnType));
+ }
+ catch (Exception ee)
+ {
+ throw new XmlException("unable to evaluate: " + _expr, ee);
+ }
+ }
+
+
+ /**
* Resolver for variable references.
*/
private class MyVariableResolver
Modified: trunk/src/test/java/net/sf/practicalxml/xpath/TestXPathWrapper.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/xpath/TestXPathWrapper.java 2008-12-30 14:01:57 UTC (rev 69)
+++ trunk/src/test/java/net/sf/practicalxml/xpath/TestXPathWrapper.java 2008-12-30 14:08:10 UTC (rev 70)
@@ -104,7 +104,7 @@
List<Node> result1 = xpath.evaluate(_dom);
assertEquals(1, result1.size());
- assertSame(_root, result1.get(0));
+ assertSame(_dom, result1.get(0));
List<Node> result2 = xpath.evaluate(_root);
assertEquals(1, result2.size());
@@ -123,9 +123,7 @@
_root.setAttribute("argle", "bargle");
XPathWrapper xpath = new XPathWrapper("@foo");
-
assertEquals("bar", xpath.evaluateAsString(_root));
- assertEquals("bar", xpath.evaluateAsString(_dom));
}
@@ -135,9 +133,7 @@
_root.setAttribute("foo", "10");
XPathWrapper xpath = new XPathWrapper("@foo");
-
- assertEquals(Double.valueOf(10.0), xpath.evaluateAsNumber(_root));
- assertEquals(Double.valueOf(10.0), xpath.evaluateAsNumber(_dom));
+ assertEquals(10, xpath.evaluateAsNumber(_root).intValue());
}
@@ -147,14 +143,13 @@
_root.setAttribute("foo", "10");
XPathWrapper xpath1 = new XPathWrapper("@foo=10");
-
assertTrue(xpath1.evaluateAsBoolean(_root).booleanValue());
- assertTrue(xpath1.evaluateAsBoolean(_dom).booleanValue());
_root.setAttribute("foo", "20");
-
assertFalse(xpath1.evaluateAsBoolean(_root).booleanValue());
- assertFalse(xpath1.evaluateAsBoolean(_dom).booleanValue());
+
+ XPathWrapper xpath2 = new XPathWrapper(".");
+ assertTrue(xpath2.evaluateAsBoolean(_root).booleanValue());
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-30 14:02:01
|
Revision: 69
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=69&view=rev
Author: kdgregory
Date: 2008-12-30 14:01:57 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
Rename DomUtil.toList() to asList() -- consistent with Arrays.asList()
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/DomUtil.java
trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java
Modified: trunk/src/main/java/net/sf/practicalxml/DomUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/DomUtil.java 2008-12-30 13:49:58 UTC (rev 68)
+++ trunk/src/main/java/net/sf/practicalxml/DomUtil.java 2008-12-30 14:01:57 UTC (rev 69)
@@ -449,7 +449,7 @@
* @throws ClassCastException if any node in the list is not the expected
* type.
*/
- public static <T> List<T> toList(NodeList nodelist, Class<T> ofClass)
+ public static <T> List<T> asList(NodeList nodelist, Class<T> ofClass)
{
int size = nodelist.getLength();
List<T> result = new ArrayList<T>(size);
Modified: trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java 2008-12-30 13:49:58 UTC (rev 68)
+++ trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java 2008-12-30 14:01:57 UTC (rev 69)
@@ -318,7 +318,7 @@
DomUtil.setText(root, "blah blah blah");
Element child2 = DomUtil.appendChild(root, "foo");
- List<Element> result = DomUtil.toList(root.getElementsByTagName("*"), Element.class);
+ List<Element> result = DomUtil.asList(root.getElementsByTagName("*"), Element.class);
assertEquals(2, result.size());
assertSame(child1, result.get(0));
assertSame(child2, result.get(1));
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-30 13:50:02
|
Revision: 68
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=68&view=rev
Author: kdgregory
Date: 2008-12-30 13:49:58 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
DomUtil.toList()
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/DomUtil.java
trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java
Modified: trunk/src/main/java/net/sf/practicalxml/DomUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/DomUtil.java 2008-12-29 02:57:43 UTC (rev 67)
+++ trunk/src/main/java/net/sf/practicalxml/DomUtil.java 2008-12-30 13:49:58 UTC (rev 68)
@@ -440,6 +440,28 @@
/**
+ * Creates a paramaterized list from a <code>NodeList</code>, making it
+ * usable within the Java coding idiom.
+ *
+ * @param nodelist The list of nodes to convert.
+ * @param ofClass The type of the nodes being converted.
+ *
+ * @throws ClassCastException if any node in the list is not the expected
+ * type.
+ */
+ public static <T> List<T> toList(NodeList nodelist, Class<T> ofClass)
+ {
+ int size = nodelist.getLength();
+ List<T> result = new ArrayList<T>(size);
+ for (int ii = 0 ; ii < size ; ii++)
+ {
+ result.add(ofClass.cast(nodelist.item(ii)));
+ }
+ return result;
+ }
+
+
+ /**
* Returns the path from the root of the document to the specified
* element, consisting of each node's qualified name, separated by
* slashes. Accepts an arbitrary number of attribute names, and
@@ -697,6 +719,6 @@
if (sibling == elem)
return elemPos;
}
- throw new IllegalArgumentException("element not amongs its siblings");
+ throw new IllegalArgumentException("element not amongst its siblings");
}
}
Modified: trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java 2008-12-29 02:57:43 UTC (rev 67)
+++ trunk/src/test/java/net/sf/practicalxml/TestDomUtil.java 2008-12-30 13:49:58 UTC (rev 68)
@@ -309,4 +309,18 @@
// success
}
}
+
+
+ public void testToList() throws Exception
+ {
+ Element root = DomUtil.newDocument("foo");
+ Element child1 = DomUtil.appendChild(root, "foo");
+ DomUtil.setText(root, "blah blah blah");
+ Element child2 = DomUtil.appendChild(root, "foo");
+
+ List<Element> result = DomUtil.toList(root.getElementsByTagName("*"), Element.class);
+ assertEquals(2, result.size());
+ assertSame(child1, result.get(0));
+ assertSame(child2, result.get(1));
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-29 02:57:47
|
Revision: 67
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=67&view=rev
Author: kdgregory
Date: 2008-12-29 02:57:43 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
SchemaUtil: change access level of internal nested classes
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java
Modified: trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java 2008-12-29 02:52:04 UTC (rev 66)
+++ trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java 2008-12-29 02:57:43 UTC (rev 67)
@@ -230,10 +230,9 @@
* are different under 1.6, it will be moved into its own package and
* accessed via a factory.
* <p>
- * Defined as protected -- as are internal methods -- so that it can be
- * tested independently.
+ * Defined as package protected so that it can be tested independently.
*/
- protected static class SchemaManager
+ static class SchemaManager
{
private HashMap<String,Document> _documents = new HashMap<String,Document>();
@@ -319,9 +318,9 @@
* namespace URLs, and schemas with no target namespace are greater-than
* those with (since they cannot be imported).
* <p>
- * Defined as protected so that it can be tested independently.
+ * Defined as package-protected so that it can be tested independently.
*/
- protected static class SchemaComparator
+ static class SchemaComparator
implements Comparator<Document>
{
public int compare(Document o1, Document o2)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-29 02:52:08
|
Revision: 66
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=66&view=rev
Author: kdgregory
Date: 2008-12-29 02:52:04 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
XsiBoolean
Added Paths:
-----------
trunk/src/main/java/net/sf/practicalxml/xpath/function/XsiBoolean.java
trunk/src/test/java/net/sf/practicalxml/xpath/function/TestXsiBoolean.java
Added: trunk/src/main/java/net/sf/practicalxml/xpath/function/XsiBoolean.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/function/XsiBoolean.java (rev 0)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/function/XsiBoolean.java 2008-12-29 02:52:04 UTC (rev 66)
@@ -0,0 +1,69 @@
+package net.sf.practicalxml.xpath.function;
+
+import org.w3c.dom.Node;
+
+import net.sf.practicalxml.xpath.AbstractFunction;
+
+
+/**
+ * Converts its argument to a boolean value, using a modification of the rules
+ * for Schema instances: true is represented by the literal values "true" or
+ * 1, ignoring case, while false is everything else. This is very different
+ * from the XPath function <code>boolean()</code>, in which any non-zero value
+ * or non-empty string/nodeset is true.
+ * <p>
+ * Note: the name of this class is <code>XsiBoolean</code>, but it's name in
+ * an XPath expression is "<code>boolean</code>". This is to prevent name
+ * collision with <code>java.lang.Boolean</code>.
+ */
+public class XsiBoolean
+extends AbstractFunction<Boolean>
+{
+ public XsiBoolean()
+ {
+ super(Constants.COMMON_NS_URI, "boolean", 1);
+ }
+
+
+ @Override
+ protected Boolean processArg(int index, Node value, Boolean helper)
+ throws Exception
+ {
+ return (value != null)
+ ? processArg(index, value.getTextContent(), helper)
+ : Boolean.FALSE;
+ }
+
+
+ @Override
+ protected Boolean processArg(int index, String value, Boolean helper)
+ throws Exception
+ {
+ return "true".equals(value.toLowerCase())
+ || "1".equals(value);
+ }
+
+
+ @Override
+ protected Boolean processArg(int index, Boolean value, Boolean helper)
+ throws Exception
+ {
+ return value;
+ }
+
+
+ @Override
+ protected Boolean processArg(int index, Number value, Boolean helper)
+ throws Exception
+ {
+ return Boolean.valueOf(value.intValue() == 1);
+ }
+
+
+ @Override
+ protected Boolean processNullArg(int index, Boolean helper)
+ throws Exception
+ {
+ return Boolean.FALSE;
+ }
+}
\ No newline at end of file
Added: trunk/src/test/java/net/sf/practicalxml/xpath/function/TestXsiBoolean.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/xpath/function/TestXsiBoolean.java (rev 0)
+++ trunk/src/test/java/net/sf/practicalxml/xpath/function/TestXsiBoolean.java 2008-12-29 02:52:04 UTC (rev 66)
@@ -0,0 +1,183 @@
+package net.sf.practicalxml.xpath.function;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.xml.xpath.XPathFunctionException;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import net.sf.practicalxml.AbstractTestCase;
+import net.sf.practicalxml.DomUtil;
+import net.sf.practicalxml.xpath.XPathWrapper;
+
+
+public class TestXsiBoolean
+extends AbstractTestCase
+{
+ public TestXsiBoolean(String name)
+ {
+ super(name);
+ }
+
+
+//----------------------------------------------------------------------------
+// Setup
+//----------------------------------------------------------------------------
+
+ private Element _root;
+ private Element _child1;
+ private Element _child2;
+ private Element _child3;
+ private Element _child4;
+ private Element _child5;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ _root = DomUtil.newDocument("foo");
+ _child1 = DomUtil.appendChild(_root, "bar");
+ _child2 = DomUtil.appendChild(_root, "baz");
+ _child3 = DomUtil.appendChild(_root, "false");
+ _child4 = DomUtil.appendChild(_root, "true");
+ _child5 = DomUtil.appendChild(_root, "x");
+
+ DomUtil.setText(_child1, "true");
+ DomUtil.setText(_child2, "false");
+ DomUtil.setText(_child3, "1");
+ DomUtil.setText(_child4, "0");
+
+ _child1.setAttribute("attr", "False");
+ _child2.setAttribute("attr", "True");
+ _child3.setAttribute("attr", "0");
+ _child4.setAttribute("attr", "1");
+ }
+
+
+//----------------------------------------------------------------------------
+// Test Cases
+//----------------------------------------------------------------------------
+
+ public void testConstruction() throws Exception
+ {
+ XsiBoolean fn = new XsiBoolean();
+ assertEquals(Constants.COMMON_NS_URI, fn.getNamespaceUri());
+ assertEquals("boolean", fn.getName());
+ assertEquals(1, fn.getMinArgCount());
+ assertEquals(1, fn.getMaxArgCount());
+ }
+
+
+ public void testLiteralString() throws Exception
+ {
+ assertEquals(
+ Boolean.TRUE,
+ new XsiBoolean().evaluate(Arrays.asList("true")));
+ assertEquals(
+ Boolean.FALSE,
+ new XsiBoolean().evaluate(Arrays.asList("false")));
+ assertEquals(
+ Boolean.TRUE,
+ new XsiBoolean().evaluate(Arrays.asList("TrUe")));
+ assertEquals(
+ Boolean.FALSE,
+ new XsiBoolean().evaluate(Arrays.asList("FaLsE")));
+ assertEquals(
+ Boolean.TRUE,
+ new XsiBoolean().evaluate(Arrays.asList("1")));
+ assertEquals(
+ Boolean.FALSE,
+ new XsiBoolean().evaluate(Arrays.asList("0")));
+ assertEquals(
+ Boolean.FALSE,
+ new XsiBoolean().evaluate(Arrays.asList("zippy")));
+ }
+
+
+ public void testLiteralNumber() throws Exception
+ {
+ assertEquals(
+ Boolean.TRUE,
+ new XsiBoolean().evaluate(Arrays.asList(Double.valueOf(1))));
+ assertEquals(
+ Boolean.FALSE,
+ new XsiBoolean().evaluate(Arrays.asList(Double.valueOf(0))));
+ assertEquals(
+ Boolean.FALSE,
+ new XsiBoolean().evaluate(Arrays.asList(Double.valueOf(10))));
+ }
+
+
+ public void testNodeList() throws Exception
+ {
+ assertEquals(
+ Boolean.TRUE,
+ new XsiBoolean().evaluate(Arrays.asList(_root.getChildNodes())));
+ }
+
+
+ public void testNode() throws Exception
+ {
+ assertEquals(
+ Boolean.TRUE,
+ new XsiBoolean().evaluate(Arrays.asList(_child1)));
+ assertEquals(
+ Boolean.FALSE,
+ new XsiBoolean().evaluate(Arrays.asList(_child2)));
+ assertEquals(
+ Boolean.TRUE,
+ new XsiBoolean().evaluate(Arrays.asList(_child3)));
+ assertEquals(
+ Boolean.FALSE,
+ new XsiBoolean().evaluate(Arrays.asList(_child4)));
+ }
+
+
+ public void testEmptyNodeList() throws Exception
+ {
+ assertEquals(
+ Boolean.FALSE,
+ new XsiBoolean().evaluate(Arrays.asList(_child5.getChildNodes())));
+ }
+
+
+ public void testNull() throws Exception
+ {
+ assertEquals(
+ Boolean.FALSE,
+ new XsiBoolean().evaluate(Arrays.asList((String)null)));
+ }
+
+
+ public void testEmptyArglist() throws Exception
+ {
+ try
+ {
+ new XsiBoolean().evaluate(Collections.<String>emptyList());
+ fail("didn't throw on empty list");
+ }
+ catch (XPathFunctionException e)
+ {
+ // success
+ }
+ }
+
+
+ public void testInSitu() throws Exception
+ {
+ XPathWrapper xpath1 = new XPathWrapper("//*[ns:boolean(text())]")
+ .bindFunction(new XsiBoolean(), "ns");
+ List<Node> result1 = xpath1.evaluate(_root);
+ assertEquals(2, result1.size());
+ assertSame(_child1, result1.get(0));
+ assertSame(_child3, result1.get(1));
+
+ XPathWrapper xpath2 = new XPathWrapper("//*[ns:boolean(@attr)]")
+ .bindFunction(new XsiBoolean(), "ns");
+ List<Node> result2 = xpath2.evaluate(_root);
+ assertEquals(2, result2.size());
+ assertSame(_child2, result2.get(0));
+ assertSame(_child4, result2.get(1));
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-29 01:56:42
|
Revision: 65
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=65&view=rev
Author: kdgregory
Date: 2008-12-29 01:31:37 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
AbstractFunction: wasn't handling Number arguments
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java
trunk/src/test/java/net/sf/practicalxml/xpath/TestAbstractFunction.java
Modified: trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java 2008-12-29 00:42:26 UTC (rev 64)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java 2008-12-29 01:31:37 UTC (rev 65)
@@ -280,6 +280,8 @@
{
if (arg instanceof String)
helper = processArg(idx, (String)arg, helper);
+ else if (arg instanceof Number)
+ helper = processArg(idx, (Number)arg, helper);
else if (arg instanceof NodeList)
helper = processArg(idx, (NodeList)arg, helper);
else if (arg instanceof Node)
Modified: trunk/src/test/java/net/sf/practicalxml/xpath/TestAbstractFunction.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/xpath/TestAbstractFunction.java 2008-12-29 00:42:26 UTC (rev 64)
+++ trunk/src/test/java/net/sf/practicalxml/xpath/TestAbstractFunction.java 2008-12-29 01:31:37 UTC (rev 65)
@@ -228,6 +228,22 @@
}
+ public void testEvaluateNumber() throws Exception
+ {
+ List args = Arrays.asList(new Object[] {Integer.valueOf(10)});
+ MyMockFunction fn = new MyMockFunction("zippy");
+
+ assertEquals("zippy", fn.evaluate(args));
+ assertEquals(1, fn._initCalls);
+ assertEquals(0, fn._processStringCalls);
+ assertEquals(1, fn._processNumberCalls);
+ assertEquals(0, fn._processBooleanCalls);
+ assertEquals(0, fn._procesNodeCalls);
+ assertEquals(0, fn._procesNodeListCalls);
+ assertEquals(1, fn._getResultCalls);
+ }
+
+
public void testEvaluateNode() throws Exception
{
// since any JDK Node implementation is also a NodeList, we have to
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-29 00:42:29
|
Revision: 64
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=64&view=rev
Author: kdgregory
Date: 2008-12-29 00:42:26 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
XPathWrapper: move to xpath package
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/junit/DomAsserts.java
trunk/src/test/java/net/sf/practicalxml/junit/TestDomAsserts.java
trunk/src/test/java/net/sf/practicalxml/xpath/function/TestLowercase.java
trunk/src/test/java/net/sf/practicalxml/xpath/function/TestUppercase.java
Added Paths:
-----------
trunk/src/main/java/net/sf/practicalxml/xpath/XPathWrapper.java
trunk/src/test/java/net/sf/practicalxml/xpath/TestXPathWrapper.java
Removed Paths:
-------------
trunk/src/main/java/net/sf/practicalxml/XPathWrapper.java
trunk/src/test/java/net/sf/practicalxml/TestXPathWrapper.java
Deleted: trunk/src/main/java/net/sf/practicalxml/XPathWrapper.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/XPathWrapper.java 2008-12-29 00:35:16 UTC (rev 63)
+++ trunk/src/main/java/net/sf/practicalxml/XPathWrapper.java 2008-12-29 00:42:26 UTC (rev 64)
@@ -1,465 +0,0 @@
-package net.sf.practicalxml;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.xml.namespace.QName;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
-import javax.xml.xpath.XPathFunction;
-import javax.xml.xpath.XPathVariableResolver;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import net.sf.practicalxml.xpath.AbstractFunction;
-import net.sf.practicalxml.xpath.FunctionResolver;
-import net.sf.practicalxml.xpath.NamespaceResolver;
-
-
-
-/**
- * This class simplifies the use of XPath expressions, hiding the factory and
- * return types, and providing a simple builder-style interface for adding
- * resolvers. It also maintains the expression in a compiled form, improving
- * reuse performance.
- */
-public class XPathWrapper
-{
- private final String _expr;
- private final NamespaceResolver _nsResolver = new NamespaceResolver();
- private Map<QName,Object> _variables = new HashMap<QName,Object>();
- private FunctionResolver _functions = new FunctionResolver();
-
- private XPathExpression _compiled;
-
-
- /**
- * Creates a new instance, which may then be customized with various
- * resolvers, and used to evaluate expressions.
- */
- public XPathWrapper(String expr)
- {
- _expr = expr;
- }
-
-
-//----------------------------------------------------------------------------
-// Public methods
-//----------------------------------------------------------------------------
-
- /**
- * Adds a namespace binding to this expression. All bindings must be
- * added prior to the first call to <code>evaluate()</code>.
- *
- * @param prefix The prefix used to reference this namespace in the
- * XPath expression. Note that this does <em>not</em>
- * need to be the same prefix used by the document.
- * @param nsURI The namespace URI to associate with this prefix.
- *
- * @return The wrapper, so that calls may be chained.
- */
- public XPathWrapper bindNamespace(String prefix, String nsURI)
- {
- _nsResolver.addNamespace(prefix, nsURI);
- return this;
- }
-
-
- /**
- * Sets the default namespace binding: this will be applied to all
- * expressions that do not explicitly specify a prefix (although
- * they must use the colon separating the non-existent prefix from
- * the element name).
- *
- * @param nsURI The default namespace for this document.
- *
- * @return The wrapper, so that calls may be chained.
- */
- public XPathWrapper bindDefaultNamespace(String nsURI)
- {
- _nsResolver.setDefaultNamespace(nsURI);
- return this;
- }
-
-
- /**
- * Binds a value to a variable, replacing any previous value for that
- * variable. Unlike other configuration methods, this may be called
- * after calling <code>evaluate()</code>; the new values will be used
- * for subsequent evaluations.
- *
- * @param name The name of the variable; this is turned into a
- * <code>QName</code> without namespace.
- * @param value The value of the variable; the XPath evaluator must
- * be able to convert this value into a type usable in
- * an XPath expression.
- *
- * @return The wrapper, so that calls may be chained.
- */
- public XPathWrapper bindVariable(String name, Object value)
- {
- return bindVariable(new QName(name), value);
- }
-
-
- /**
- * Binds a value to a variable, replacing any previous value for that
- * variable. Unlike other configuration methods, this may be called
- * after calling <code>evaluate()</code>; the new values will be used
- * for subsequent evaluations.
- *
- * @param name The fully-qualified name of the variable.
- * @param value The value of the variable; the XPath evaluator must
- * be able to convert this value into a type usable in
- * an XPath expression.
- *
- * @return The wrapper, so that calls may be chained.
- */
- public XPathWrapper bindVariable(QName name, Object value)
- {
- _variables.put(name, value);
- return this;
- }
-
-
- /**
- * Binds an {@link net.sf.practicalxml.xpath.AbstractFunction} to this
- * expression. Subsequent calls to this method with the same name will
- * silently replace the binding.
- * <p>
- * Per the JDK documentation, user-defined functions must occupy their
- * own namespace. You must bind a namespace for this function, and use
- * the bound prefix to reference it in your expression. Alternatively,
- * you can call the variant of <code>bindFunction()</code> that binds
- * a prefix to the function's namespace.
- *
- * @param func The function.
- *
- * @return The wrapper, so that calls may be chained.
- */
- public XPathWrapper bindFunction(AbstractFunction func)
- {
- _functions.addFunction(func);
- return this;
- }
-
-
- /**
- * Binds an {@link net.sf.practicalxml.xpath.AbstractFunction} to this
- * expression, along with the prefix used to access that function.
- * Subsequent calls to this method with the same name will silently
- * replace the binding.
- * <p>
- * Per the JDK documentation, user-defined functions must occupy their
- * own namespace. This method will retrieve the namespace from the
- * function, and bind it to the passed prefix.
- *
- * @param func The function.
- * @param prefix The prefix to bind to this function's namespace.
- *
- * @return The wrapper, so that calls may be chained.
- */
- public XPathWrapper bindFunction(AbstractFunction func, String prefix)
- {
- _functions.addFunction(func);
- return bindNamespace(prefix, func.getNamespaceUri());
- }
-
-
- /**
- * Binds a standard <code>XPathFunction</code> to this expression,
- * handling any number of arguments. Subsequent calls to this method
- * with the same name will silently replace the binding.
- * <p>
- * Per the JDK documentation, user-defined functions must occupy their
- * own namespace. If the qualified name that you pass to this method
- * includes a prefix, the associated namespace will be bound to that
- * prefix. If not, you must bind the namespace explicitly. In either
- * case, you must refer to the function in your expression using a
- * bound prefix.
- *
- * @param name The qualified name for this function. Must contain
- * a name and namespace, may contain a prefix.
- * @param func The function to bind to this name.
- *
- * @return The wrapper, so that calls may be chained.
- */
- public XPathWrapper bindFunction(QName name, XPathFunction func)
- {
- return bindFunction(name, func, 0, Integer.MAX_VALUE);
- }
-
-
- /**
- * Binds a standard <code>XPathFunction</code> to this expression,
- * handling a specific number of arguments. Subsequent calls to this
- * method with the same name and arity will silently replace the binding.
- * <p>
- * Per the JDK documentation, user-defined functions must occupy their
- * own namespace. If the qualified name that you pass to this method
- * includes a prefix, the associated namespace will be bound to that
- * prefix. If not, you must bind the namespace explicitly. In either
- * case, you must refer to the function in your expression using a
- * bound prefix.
- *
- * @param name The qualified name for this function. Must contain
- * a name and namespace, may contain a prefix.
- * @param func The function to bind to this name.
- * @param arity The number of arguments accepted by this function.
- *
- * @return The wrapper, so that calls may be chained.
- */
- public XPathWrapper bindFunction(QName name, XPathFunction func, int arity)
- {
- return bindFunction(name, func, arity, arity);
- }
-
-
- /**
- * Binds a standard <code>XPathFunction</code> to this expression,
- * handling a specific range of arguments. Subsequent calls to this
- * method with the same name and range of arguments will silently
- * replace the binding.
- * <p>
- * Per the JDK documentation, user-defined functions must occupy their
- * own namespace. If the qualified name that you pass to this method
- * includes a prefix, the associated namespace will be bound to that
- * prefix. If not, you must bind the namespace explicitly. In either
- * case, you must refer to the function in your expression using a
- * bound prefix.
- *
- * @param name The qualified name for this function. Must contain
- * a name and namespace, may contain a prefix.
- * @param func The function to bind to this name.
- * @param minArity The minimum number of arguments accepted by this
- * function.
- * @param maxArity The maximum number of arguments accepted by this
- * function.
- *
- * @return The wrapper, so that calls may be chained.
- */
- public XPathWrapper bindFunction(QName name, XPathFunction func,
- int minArity, int maxArity)
- {
- _functions.addFunction(func, name, minArity, maxArity);
- if (!"".equals(name.getPrefix()))
- bindNamespace(name.getPrefix(), name.getNamespaceURI());
- return this;
- }
-
-
- /**
- * Applies this expression to the root of the specified document,
- * converting the resulting NodeList into a java.util.List for ease
- * in iteration.
- */
- public List<Node> evaluate(Document context)
- {
- return evaluate(context.getDocumentElement());
- }
-
-
- /**
- * Applies this expression to the specified element, converting the
- * resulting NodeList into a java.util.List for ease in iteration.
- */
- public List<Node> evaluate(Element context)
- {
- compileIfNeeded();
- try
- {
- NodeList result = (NodeList)_compiled.evaluate(context, XPathConstants.NODESET);
- List<Node> ret = new ArrayList<Node>(result.getLength());
- for (int ii = 0 ; ii < result.getLength() ; ii++)
- {
- ret.add(result.item(ii));
- }
- return ret;
- }
- catch (Exception ee)
- {
- throw new XmlException("unable to evaluate: " + _expr, ee);
- }
- }
-
-
- /**
- * Applies this expression to the root of the specified document,
- * requesting the <code>STRING</code> return type.
- */
- public String evaluateAsString(Document context)
- {
- return evaluateAsString(context.getDocumentElement());
- }
-
-
- /**
- * Applies this expression to the specified element, requesting the
- * <code>STRING</code> return type.
- */
- public String evaluateAsString(Element context)
- {
- compileIfNeeded();
- try
- {
- return _compiled.evaluate(context);
- }
- catch (Exception ee)
- {
- throw new XmlException("unable to evaluate: " + _expr, ee);
- }
- }
-
-
- /**
- * Applies this expression to the root of the specified document,
- * requesting the <code>NUMBER</code> return type.
- */
- public Double evaluateAsNumber(Document context)
- {
- return evaluateAsNumber(context.getDocumentElement());
- }
-
-
- /**
- * Applies this expression to the specified element, requesting the
- * <code>NUMBER</code> return type.
- */
- public Double evaluateAsNumber(Element context)
- {
- compileIfNeeded();
- try
- {
- return (Double)_compiled.evaluate(context, XPathConstants.NUMBER);
- }
- catch (Exception ee)
- {
- throw new XmlException("unable to evaluate: " + _expr, ee);
- }
- }
-
-
- /**
- * Applies this expression to the root of the specified document,
- * requesting the <code>BOOLEAN</code> return type.
- */
- public Boolean evaluateAsBoolean(Document context)
- {
- return evaluateAsBoolean(context.getDocumentElement());
- }
-
-
- /**
- * Applies this expression to the specified element, requesting the
- * <code>BOOLEAN</code> return type.
- */
- public Boolean evaluateAsBoolean(Element context)
- {
- compileIfNeeded();
- try
- {
- return (Boolean)_compiled.evaluate(context, XPathConstants.BOOLEAN);
- }
- catch (Exception ee)
- {
- throw new XmlException("unable to evaluate: " + _expr, ee);
- }
- }
-
-
-//----------------------------------------------------------------------------
-// Overrides of Object
-//----------------------------------------------------------------------------
-
-
- /**
- * Two instances are considered equal if they have the same expression,
- * namespace mappings, variable mappings, and function mappings. Note
- * that instances with function mappings are all but guaranteed to be
- * not-equal, unless you override the <code>equals()</code> method on
- * the function implementation class.
- */
- @Override
- public final boolean equals(Object obj)
- {
- if (obj instanceof XPathWrapper)
- {
- XPathWrapper that = (XPathWrapper)obj;
- return this._expr.equals(that._expr)
- && this._nsResolver.equals(that._nsResolver)
- && this._variables.equals(that._variables)
- && this._functions.equals(that._functions);
- }
- return false;
- }
-
-
- /**
- * Hash code is driven by the expression, ignoring differences between
- * namespaces, variables, and functions.
- */
- @Override
- public int hashCode()
- {
- return _expr.hashCode();
- }
-
-
- /**
- * The string value is the expression.
- */
- @Override
- public String toString()
- {
- return _expr;
- }
-
-
-//----------------------------------------------------------------------------
-// Internals
-//----------------------------------------------------------------------------
-
- /**
- * Compiles the expression, if it has not already been compiled. This is
- * called from the various <code>evaluate</code> methods, and ensures
- * that the caller has completely configured the wrapper prior to use.
- */
- private void compileIfNeeded()
- {
- if (_compiled != null)
- return;
-
- try
- {
- XPath xpath = XPathFactory.newInstance().newXPath();
- xpath.setNamespaceContext(_nsResolver);
- xpath.setXPathVariableResolver(new MyVariableResolver());
- xpath.setXPathFunctionResolver(_functions);
- _compiled = xpath.compile(_expr);
- }
- catch (XPathExpressionException ee)
- {
- throw new XmlException("unable to compile: " + _expr, ee);
- }
- }
-
-
- /**
- * Resolver for variable references.
- */
- private class MyVariableResolver
- implements XPathVariableResolver
- {
- public Object resolveVariable(QName name)
- {
- return _variables.get(name);
- }
- }
-}
Modified: trunk/src/main/java/net/sf/practicalxml/junit/DomAsserts.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/junit/DomAsserts.java 2008-12-29 00:35:16 UTC (rev 63)
+++ trunk/src/main/java/net/sf/practicalxml/junit/DomAsserts.java 2008-12-29 00:42:26 UTC (rev 64)
@@ -7,7 +7,7 @@
import junit.framework.Assert;
import net.sf.practicalxml.DomUtil;
-import net.sf.practicalxml.XPathWrapper;
+import net.sf.practicalxml.xpath.XPathWrapper;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
Copied: trunk/src/main/java/net/sf/practicalxml/xpath/XPathWrapper.java (from rev 63, trunk/src/main/java/net/sf/practicalxml/XPathWrapper.java)
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/XPathWrapper.java (rev 0)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/XPathWrapper.java 2008-12-29 00:42:26 UTC (rev 64)
@@ -0,0 +1,463 @@
+package net.sf.practicalxml.xpath;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathVariableResolver;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import net.sf.practicalxml.XmlException;
+
+
+
+/**
+ * This class simplifies the use of XPath expressions, hiding the factory and
+ * return types, and providing a simple builder-style interface for adding
+ * resolvers. It also maintains the expression in a compiled form, improving
+ * reuse performance.
+ */
+public class XPathWrapper
+{
+ private final String _expr;
+ private final NamespaceResolver _nsResolver = new NamespaceResolver();
+ private Map<QName,Object> _variables = new HashMap<QName,Object>();
+ private FunctionResolver _functions = new FunctionResolver();
+
+ private XPathExpression _compiled;
+
+
+ /**
+ * Creates a new instance, which may then be customized with various
+ * resolvers, and used to evaluate expressions.
+ */
+ public XPathWrapper(String expr)
+ {
+ _expr = expr;
+ }
+
+
+//----------------------------------------------------------------------------
+// Public methods
+//----------------------------------------------------------------------------
+
+ /**
+ * Adds a namespace binding to this expression. All bindings must be
+ * added prior to the first call to <code>evaluate()</code>.
+ *
+ * @param prefix The prefix used to reference this namespace in the
+ * XPath expression. Note that this does <em>not</em>
+ * need to be the same prefix used by the document.
+ * @param nsURI The namespace URI to associate with this prefix.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindNamespace(String prefix, String nsURI)
+ {
+ _nsResolver.addNamespace(prefix, nsURI);
+ return this;
+ }
+
+
+ /**
+ * Sets the default namespace binding: this will be applied to all
+ * expressions that do not explicitly specify a prefix (although
+ * they must use the colon separating the non-existent prefix from
+ * the element name).
+ *
+ * @param nsURI The default namespace for this document.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindDefaultNamespace(String nsURI)
+ {
+ _nsResolver.setDefaultNamespace(nsURI);
+ return this;
+ }
+
+
+ /**
+ * Binds a value to a variable, replacing any previous value for that
+ * variable. Unlike other configuration methods, this may be called
+ * after calling <code>evaluate()</code>; the new values will be used
+ * for subsequent evaluations.
+ *
+ * @param name The name of the variable; this is turned into a
+ * <code>QName</code> without namespace.
+ * @param value The value of the variable; the XPath evaluator must
+ * be able to convert this value into a type usable in
+ * an XPath expression.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindVariable(String name, Object value)
+ {
+ return bindVariable(new QName(name), value);
+ }
+
+
+ /**
+ * Binds a value to a variable, replacing any previous value for that
+ * variable. Unlike other configuration methods, this may be called
+ * after calling <code>evaluate()</code>; the new values will be used
+ * for subsequent evaluations.
+ *
+ * @param name The fully-qualified name of the variable.
+ * @param value The value of the variable; the XPath evaluator must
+ * be able to convert this value into a type usable in
+ * an XPath expression.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindVariable(QName name, Object value)
+ {
+ _variables.put(name, value);
+ return this;
+ }
+
+
+ /**
+ * Binds an {@link net.sf.practicalxml.xpath.AbstractFunction} to this
+ * expression. Subsequent calls to this method with the same name will
+ * silently replace the binding.
+ * <p>
+ * Per the JDK documentation, user-defined functions must occupy their
+ * own namespace. You must bind a namespace for this function, and use
+ * the bound prefix to reference it in your expression. Alternatively,
+ * you can call the variant of <code>bindFunction()</code> that binds
+ * a prefix to the function's namespace.
+ *
+ * @param func The function.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindFunction(AbstractFunction func)
+ {
+ _functions.addFunction(func);
+ return this;
+ }
+
+
+ /**
+ * Binds an {@link net.sf.practicalxml.xpath.AbstractFunction} to this
+ * expression, along with the prefix used to access that function.
+ * Subsequent calls to this method with the same name will silently
+ * replace the binding.
+ * <p>
+ * Per the JDK documentation, user-defined functions must occupy their
+ * own namespace. This method will retrieve the namespace from the
+ * function, and bind it to the passed prefix.
+ *
+ * @param func The function.
+ * @param prefix The prefix to bind to this function's namespace.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindFunction(AbstractFunction func, String prefix)
+ {
+ _functions.addFunction(func);
+ return bindNamespace(prefix, func.getNamespaceUri());
+ }
+
+
+ /**
+ * Binds a standard <code>XPathFunction</code> to this expression,
+ * handling any number of arguments. Subsequent calls to this method
+ * with the same name will silently replace the binding.
+ * <p>
+ * Per the JDK documentation, user-defined functions must occupy their
+ * own namespace. If the qualified name that you pass to this method
+ * includes a prefix, the associated namespace will be bound to that
+ * prefix. If not, you must bind the namespace explicitly. In either
+ * case, you must refer to the function in your expression using a
+ * bound prefix.
+ *
+ * @param name The qualified name for this function. Must contain
+ * a name and namespace, may contain a prefix.
+ * @param func The function to bind to this name.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindFunction(QName name, XPathFunction func)
+ {
+ return bindFunction(name, func, 0, Integer.MAX_VALUE);
+ }
+
+
+ /**
+ * Binds a standard <code>XPathFunction</code> to this expression,
+ * handling a specific number of arguments. Subsequent calls to this
+ * method with the same name and arity will silently replace the binding.
+ * <p>
+ * Per the JDK documentation, user-defined functions must occupy their
+ * own namespace. If the qualified name that you pass to this method
+ * includes a prefix, the associated namespace will be bound to that
+ * prefix. If not, you must bind the namespace explicitly. In either
+ * case, you must refer to the function in your expression using a
+ * bound prefix.
+ *
+ * @param name The qualified name for this function. Must contain
+ * a name and namespace, may contain a prefix.
+ * @param func The function to bind to this name.
+ * @param arity The number of arguments accepted by this function.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindFunction(QName name, XPathFunction func, int arity)
+ {
+ return bindFunction(name, func, arity, arity);
+ }
+
+
+ /**
+ * Binds a standard <code>XPathFunction</code> to this expression,
+ * handling a specific range of arguments. Subsequent calls to this
+ * method with the same name and range of arguments will silently
+ * replace the binding.
+ * <p>
+ * Per the JDK documentation, user-defined functions must occupy their
+ * own namespace. If the qualified name that you pass to this method
+ * includes a prefix, the associated namespace will be bound to that
+ * prefix. If not, you must bind the namespace explicitly. In either
+ * case, you must refer to the function in your expression using a
+ * bound prefix.
+ *
+ * @param name The qualified name for this function. Must contain
+ * a name and namespace, may contain a prefix.
+ * @param func The function to bind to this name.
+ * @param minArity The minimum number of arguments accepted by this
+ * function.
+ * @param maxArity The maximum number of arguments accepted by this
+ * function.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindFunction(QName name, XPathFunction func,
+ int minArity, int maxArity)
+ {
+ _functions.addFunction(func, name, minArity, maxArity);
+ if (!"".equals(name.getPrefix()))
+ bindNamespace(name.getPrefix(), name.getNamespaceURI());
+ return this;
+ }
+
+
+ /**
+ * Applies this expression to the root of the specified document,
+ * converting the resulting NodeList into a java.util.List for ease
+ * in iteration.
+ */
+ public List<Node> evaluate(Document context)
+ {
+ return evaluate(context.getDocumentElement());
+ }
+
+
+ /**
+ * Applies this expression to the specified element, converting the
+ * resulting NodeList into a java.util.List for ease in iteration.
+ */
+ public List<Node> evaluate(Element context)
+ {
+ compileIfNeeded();
+ try
+ {
+ NodeList result = (NodeList)_compiled.evaluate(context, XPathConstants.NODESET);
+ List<Node> ret = new ArrayList<Node>(result.getLength());
+ for (int ii = 0 ; ii < result.getLength() ; ii++)
+ {
+ ret.add(result.item(ii));
+ }
+ return ret;
+ }
+ catch (Exception ee)
+ {
+ throw new XmlException("unable to evaluate: " + _expr, ee);
+ }
+ }
+
+
+ /**
+ * Applies this expression to the root of the specified document,
+ * requesting the <code>STRING</code> return type.
+ */
+ public String evaluateAsString(Document context)
+ {
+ return evaluateAsString(context.getDocumentElement());
+ }
+
+
+ /**
+ * Applies this expression to the specified element, requesting the
+ * <code>STRING</code> return type.
+ */
+ public String evaluateAsString(Element context)
+ {
+ compileIfNeeded();
+ try
+ {
+ return _compiled.evaluate(context);
+ }
+ catch (Exception ee)
+ {
+ throw new XmlException("unable to evaluate: " + _expr, ee);
+ }
+ }
+
+
+ /**
+ * Applies this expression to the root of the specified document,
+ * requesting the <code>NUMBER</code> return type.
+ */
+ public Double evaluateAsNumber(Document context)
+ {
+ return evaluateAsNumber(context.getDocumentElement());
+ }
+
+
+ /**
+ * Applies this expression to the specified element, requesting the
+ * <code>NUMBER</code> return type.
+ */
+ public Double evaluateAsNumber(Element context)
+ {
+ compileIfNeeded();
+ try
+ {
+ return (Double)_compiled.evaluate(context, XPathConstants.NUMBER);
+ }
+ catch (Exception ee)
+ {
+ throw new XmlException("unable to evaluate: " + _expr, ee);
+ }
+ }
+
+
+ /**
+ * Applies this expression to the root of the specified document,
+ * requesting the <code>BOOLEAN</code> return type.
+ */
+ public Boolean evaluateAsBoolean(Document context)
+ {
+ return evaluateAsBoolean(context.getDocumentElement());
+ }
+
+
+ /**
+ * Applies this expression to the specified element, requesting the
+ * <code>BOOLEAN</code> return type.
+ */
+ public Boolean evaluateAsBoolean(Element context)
+ {
+ compileIfNeeded();
+ try
+ {
+ return (Boolean)_compiled.evaluate(context, XPathConstants.BOOLEAN);
+ }
+ catch (Exception ee)
+ {
+ throw new XmlException("unable to evaluate: " + _expr, ee);
+ }
+ }
+
+
+//----------------------------------------------------------------------------
+// Overrides of Object
+//----------------------------------------------------------------------------
+
+
+ /**
+ * Two instances are considered equal if they have the same expression,
+ * namespace mappings, variable mappings, and function mappings. Note
+ * that instances with function mappings are all but guaranteed to be
+ * not-equal, unless you override the <code>equals()</code> method on
+ * the function implementation class.
+ */
+ @Override
+ public final boolean equals(Object obj)
+ {
+ if (obj instanceof XPathWrapper)
+ {
+ XPathWrapper that = (XPathWrapper)obj;
+ return this._expr.equals(that._expr)
+ && this._nsResolver.equals(that._nsResolver)
+ && this._variables.equals(that._variables)
+ && this._functions.equals(that._functions);
+ }
+ return false;
+ }
+
+
+ /**
+ * Hash code is driven by the expression, ignoring differences between
+ * namespaces, variables, and functions.
+ */
+ @Override
+ public int hashCode()
+ {
+ return _expr.hashCode();
+ }
+
+
+ /**
+ * The string value is the expression.
+ */
+ @Override
+ public String toString()
+ {
+ return _expr;
+ }
+
+
+//----------------------------------------------------------------------------
+// Internals
+//----------------------------------------------------------------------------
+
+ /**
+ * Compiles the expression, if it has not already been compiled. This is
+ * called from the various <code>evaluate</code> methods, and ensures
+ * that the caller has completely configured the wrapper prior to use.
+ */
+ private void compileIfNeeded()
+ {
+ if (_compiled != null)
+ return;
+
+ try
+ {
+ XPath xpath = XPathFactory.newInstance().newXPath();
+ xpath.setNamespaceContext(_nsResolver);
+ xpath.setXPathVariableResolver(new MyVariableResolver());
+ xpath.setXPathFunctionResolver(_functions);
+ _compiled = xpath.compile(_expr);
+ }
+ catch (XPathExpressionException ee)
+ {
+ throw new XmlException("unable to compile: " + _expr, ee);
+ }
+ }
+
+
+ /**
+ * Resolver for variable references.
+ */
+ private class MyVariableResolver
+ implements XPathVariableResolver
+ {
+ public Object resolveVariable(QName name)
+ {
+ return _variables.get(name);
+ }
+ }
+}
Deleted: trunk/src/test/java/net/sf/practicalxml/TestXPathWrapper.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestXPathWrapper.java 2008-12-29 00:35:16 UTC (rev 63)
+++ trunk/src/test/java/net/sf/practicalxml/TestXPathWrapper.java 2008-12-29 00:42:26 UTC (rev 64)
@@ -1,339 +0,0 @@
-package net.sf.practicalxml;
-
-import java.util.List;
-import javax.xml.namespace.QName;
-import javax.xml.xpath.XPathFunction;
-import javax.xml.xpath.XPathFunctionException;
-
-import net.sf.practicalxml.xpath.AbstractFunction;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-
-public class TestXPathWrapper
-extends AbstractTestCase
-{
- public TestXPathWrapper(String name)
- {
- super(name);
- }
-
-
-//----------------------------------------------------------------------------
-// Test data
-//----------------------------------------------------------------------------
-
- public final static String EL_ROOT = "root";
- public final static String EL_CHILD = "child";
- public final static String NS1 = "ns1";
- public final static String NS2 = "ns2";
-
- Document _dom;
- Element _root;
- Element _child1;
- Element _child2;
- Element _child3;
-
- @Override
- protected void setUp()
- {
- _root = DomUtil.newDocument(EL_ROOT);
- _child1 = DomUtil.appendChild(_root, EL_CHILD);
- _child2 = DomUtil.appendChild(_root, NS1, EL_CHILD);
- _child3 = DomUtil.appendChild(_root, NS2, EL_CHILD);
- _dom = _root.getOwnerDocument();
- }
-
-
-//----------------------------------------------------------------------------
-// Support Code
-//----------------------------------------------------------------------------
-
- /**
- * A standard XPath function implementation that returns the namespace
- * of the first selected node.
- */
- private static class MyStandardFunction
- implements XPathFunction
- {
- public Object evaluate(List args)
- throws XPathFunctionException
- {
- NodeList arg = (NodeList)args.get(0);
- return arg.item(0).getNamespaceURI();
- }
- }
-
-
- /**
- * An <code>AbstractFunction</code> implementation that returns the
- * namespace of the first selected node.
- */
- private static class MyAbstractFunction
- extends AbstractFunction<String>
- {
- public MyAbstractFunction(String nsUri, String name)
- {
- super(nsUri, name);
- }
-
- @Override
- protected String processArg(int index, Node value, String helper)
- throws Exception
- {
- return value.getNamespaceURI();
- }
- }
-
-//----------------------------------------------------------------------------
-// Test Cases
-//----------------------------------------------------------------------------
-
- // the basic test to verify we can compile and execute
- public void testCurrentElement()
- throws Exception
- {
- XPathWrapper xpath = new XPathWrapper(".");
-
- List<Node> result1 = xpath.evaluate(_dom);
- assertEquals(1, result1.size());
- assertSame(_root, result1.get(0));
-
- List<Node> result2 = xpath.evaluate(_root);
- assertEquals(1, result2.size());
- assertSame(_root, result2.get(0));
-
- List<Node> result3 = xpath.evaluate(_child1);
- assertEquals(1, result3.size());
- assertSame(_child1, result3.get(0));
- }
-
-
- public void testEvalAsString()
- throws Exception
- {
- _root.setAttribute("foo", "bar");
- _root.setAttribute("argle", "bargle");
-
- XPathWrapper xpath = new XPathWrapper("@foo");
-
- assertEquals("bar", xpath.evaluateAsString(_root));
- assertEquals("bar", xpath.evaluateAsString(_dom));
- }
-
-
- public void testEvalAsNumber()
- throws Exception
- {
- _root.setAttribute("foo", "10");
-
- XPathWrapper xpath = new XPathWrapper("@foo");
-
- assertEquals(Double.valueOf(10.0), xpath.evaluateAsNumber(_root));
- assertEquals(Double.valueOf(10.0), xpath.evaluateAsNumber(_dom));
- }
-
-
- public void testEvalAsBoolean()
- throws Exception
- {
- _root.setAttribute("foo", "10");
-
- XPathWrapper xpath1 = new XPathWrapper("@foo=10");
-
- assertTrue(xpath1.evaluateAsBoolean(_root).booleanValue());
- assertTrue(xpath1.evaluateAsBoolean(_dom).booleanValue());
-
- _root.setAttribute("foo", "20");
-
- assertFalse(xpath1.evaluateAsBoolean(_root).booleanValue());
- assertFalse(xpath1.evaluateAsBoolean(_dom).booleanValue());
- }
-
-
- public void testNamespaces() throws Exception
- {
- XPathWrapper xpath1 = new XPathWrapper("//child");
- List<Node> result1 = xpath1.evaluate(_dom);
- assertEquals(1, result1.size());
- assertSame(_child1, result1.get(0));
-
- XPathWrapper xpath2 = new XPathWrapper("//ns:child")
- .bindNamespace("ns", NS1);
- List<Node> result2 = xpath2.evaluate(_dom);
- assertEquals(1, result2.size());
- assertSame(_child2, result2.get(0));
-
- XPathWrapper xpath3 = new XPathWrapper("//:child")
- .bindDefaultNamespace(NS2);
- List<Node> result3 = xpath3.evaluate(_dom);
- assertEquals(1, result3.size());
- assertSame(_child3, result3.get(0));
- }
-
-
- public void testVariables() throws Exception
- {
- _child1.setAttribute("bar", "baz");
- _child2.setAttribute("bar", "bargle");
-
- XPathWrapper xpath = new XPathWrapper("//*[@bar=$test]")
- .bindVariable(new QName("test"), "baz");
-
- List<Node> result1 = xpath.evaluate(_dom);
- assertEquals(1, result1.size());
- assertSame(_child1, result1.get(0));
-
- xpath.bindVariable("test", "bargle");
-
- List<Node> result2 = xpath.evaluate(_dom);
- assertEquals(1, result2.size());
- assertSame(_child2, result2.get(0));
- }
-
-
- public void testAbstractFunctions() throws Exception
- {
- XPathWrapper xpath1 = new XPathWrapper("ns:myfunc(.)")
- .bindNamespace("ns", NS1)
- .bindFunction(new MyAbstractFunction(NS1, "myfunc"));
-
- assertEquals("", xpath1.evaluateAsString(_child1));
- assertEquals(NS1, xpath1.evaluateAsString(_child2));
-
- XPathWrapper xpath2 = new XPathWrapper("ns:myfunc(.)")
- .bindFunction(new MyAbstractFunction(NS1, "myfunc"), "ns");
-
- assertEquals("", xpath2.evaluateAsString(_child1));
- assertEquals(NS1, xpath2.evaluateAsString(_child2));
- }
-
-
- public void testStandardFunctions() throws Exception
- {
- XPathWrapper xpath1 = new XPathWrapper("ns:myfunc(.)")
- .bindFunction(new QName(NS1, "myfunc", "ns"),
- new MyStandardFunction());
-
- assertEquals("", xpath1.evaluateAsString(_child1));
- assertEquals(NS1, xpath1.evaluateAsString(_child2));
-
- XPathWrapper xpath2 = new XPathWrapper("ns:myfunc(.,.)")
- .bindFunction(new QName(NS2, "myfunc", "ns"),
- new MyStandardFunction(),
- 2);
-
- assertEquals("", xpath2.evaluateAsString(_child1));
- assertEquals(NS1, xpath2.evaluateAsString(_child2));
- }
-
-
- public void testUnresolvableFunction() throws Exception
- {
- // we call with two arguments, it only gets resolved for one
- XPathWrapper xpath1 = new XPathWrapper("ns:myfunc(.,.)")
- .bindFunction(new QName(NS2, "myfunc", "ns"),
- new MyStandardFunction(),
- 1);
- try
- {
- xpath1.evaluateAsString(_child1);
- fail("didn't throw even though arity was wrong");
- }
- catch (XmlException ee)
- {
- // success
- }
- }
-
-
-
- public void testEqualsAndHashCode() throws Exception
- {
- Object obj1a = new XPathWrapper("//foo");
- Object obj1b = new XPathWrapper("//foo");
- Object obj2a = new XPathWrapper("//foo")
- .bindDefaultNamespace("zippy");
- Object obj2b = new XPathWrapper("//foo")
- .bindDefaultNamespace("zippy");
- Object obj3a = new XPathWrapper("//foo")
- .bindNamespace("argle", "bargle");
- Object obj3b = new XPathWrapper("//foo")
- .bindNamespace("argle", "bargle");
- Object obj4a = new XPathWrapper("//foo")
- .bindVariable("argle", "bargle");
- Object obj4b = new XPathWrapper("//foo")
- .bindVariable("argle", "bargle");
- Object obj5a = new XPathWrapper("//foo")
- .bindFunction(new QName("foo"), null);
- Object obj5b = new XPathWrapper("//foo")
- .bindFunction(new QName("foo"), null);
-
- assertFalse(obj1a.equals(null));
- assertFalse(obj1a.equals(new Object()));
-
- assertTrue(obj1a.equals(obj1b));
- assertTrue(obj1b.equals(obj1a));
- assertEquals(obj1a.hashCode(), obj1b.hashCode());
-
- assertFalse(obj1a.equals(obj2a));
- assertTrue(obj2a.equals(obj2b));
- assertTrue(obj2b.equals(obj2a));
- assertEquals(obj1a.hashCode(), obj2a.hashCode());
- assertEquals(obj2a.hashCode(), obj2b.hashCode());
-
- assertFalse(obj1a.equals(obj3a));
- assertTrue(obj3a.equals(obj3b));
- assertTrue(obj3b.equals(obj3a));
- assertEquals(obj1a.hashCode(), obj3a.hashCode());
- assertEquals(obj3a.hashCode(), obj3b.hashCode());
-
- assertFalse(obj1a.equals(obj4a));
- assertTrue(obj4a.equals(obj4b));
- assertTrue(obj4b.equals(obj4a));
- assertEquals(obj1a.hashCode(), obj4a.hashCode());
- assertEquals(obj4a.hashCode(), obj4b.hashCode());
-
- assertFalse(obj1a.equals(obj5a));
- assertTrue(obj5a.equals(obj5b));
- assertTrue(obj5b.equals(obj5a));
- assertEquals(obj1a.hashCode(), obj5a.hashCode());
- assertEquals(obj5a.hashCode(), obj5b.hashCode());
- }
-
-
- public void testToString() throws Exception
- {
- final String expr = "//foo";
- assertEquals(expr, new XPathWrapper(expr).toString());
- assertEquals(expr, new XPathWrapper(expr).bindNamespace("foo", "bar").toString());
- }
-
-
- public void testFailures() throws Exception
- {
- try
- {
- new XPathWrapper(".foo.").evaluate(_dom);
- fail("compiled invalid expression");
- }
- catch (XmlException ee)
- {
- // success
- }
-
- try
- {
- new XPathWrapper("@foo=$bar").evaluate(_dom);
- fail("evaluated expression with unbound variable");
- }
- catch (XmlException ee)
- {
- // success
- }
- }
-
-}
Modified: trunk/src/test/java/net/sf/practicalxml/junit/TestDomAsserts.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/junit/TestDomAsserts.java 2008-12-29 00:35:16 UTC (rev 63)
+++ trunk/src/test/java/net/sf/practicalxml/junit/TestDomAsserts.java 2008-12-29 00:42:26 UTC (rev 64)
@@ -7,7 +7,7 @@
import net.sf.practicalxml.AbstractTestCase;
import net.sf.practicalxml.DomUtil;
-import net.sf.practicalxml.XPathWrapper;
+import net.sf.practicalxml.xpath.XPathWrapper;
public class TestDomAsserts
Copied: trunk/src/test/java/net/sf/practicalxml/xpath/TestXPathWrapper.java (from rev 63, trunk/src/test/java/net/sf/practicalxml/TestXPathWrapper.java)
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/xpath/TestXPathWrapper.java (rev 0)
+++ trunk/src/test/java/net/sf/practicalxml/xpath/TestXPathWrapper.java 2008-12-29 00:42:26 UTC (rev 64)
@@ -0,0 +1,343 @@
+package net.sf.practicalxml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+
+import net.sf.practicalxml.AbstractTestCase;
+import net.sf.practicalxml.DomUtil;
+import net.sf.practicalxml.XmlException;
+import net.sf.practicalxml.xpath.AbstractFunction;
+import net.sf.practicalxml.xpath.XPathWrapper;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+
+public class TestXPathWrapper
+extends AbstractTestCase
+{
+ public TestXPathWrapper(String name)
+ {
+ super(name);
+ }
+
+
+//----------------------------------------------------------------------------
+// Test data
+//----------------------------------------------------------------------------
+
+ public final static String EL_ROOT = "root";
+ public final static String EL_CHILD = "child";
+ public final static String NS1 = "ns1";
+ public final static String NS2 = "ns2";
+
+ Document _dom;
+ Element _root;
+ Element _child1;
+ Element _child2;
+ Element _child3;
+
+ @Override
+ protected void setUp()
+ {
+ _root = DomUtil.newDocument(EL_ROOT);
+ _child1 = DomUtil.appendChild(_root, EL_CHILD);
+ _child2 = DomUtil.appendChild(_root, NS1, EL_CHILD);
+ _child3 = DomUtil.appendChild(_root, NS2, EL_CHILD);
+ _dom = _root.getOwnerDocument();
+ }
+
+
+//----------------------------------------------------------------------------
+// Support Code
+//----------------------------------------------------------------------------
+
+ /**
+ * A standard XPath function implementation that returns the namespace
+ * of the first selected node.
+ */
+ private static class MyStandardFunction
+ implements XPathFunction
+ {
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ NodeList arg = (NodeList)args.get(0);
+ return arg.item(0).getNamespaceURI();
+ }
+ }
+
+
+ /**
+ * An <code>AbstractFunction</code> implementation that returns the
+ * namespace of the first selected node.
+ */
+ private static class MyAbstractFunction
+ extends AbstractFunction<String>
+ {
+ public MyAbstractFunction(String nsUri, String name)
+ {
+ super(nsUri, name);
+ }
+
+ @Override
+ protected String processArg(int index, Node value, String helper)
+ throws Exception
+ {
+ return value.getNamespaceURI();
+ }
+ }
+
+//----------------------------------------------------------------------------
+// Test Cases
+//----------------------------------------------------------------------------
+
+ // the basic test to verify we can compile and execute
+ public void testCurrentElement()
+ throws Exception
+ {
+ XPathWrapper xpath = new XPathWrapper(".");
+
+ List<Node> result1 = xpath.evaluate(_dom);
+ assertEquals(1, result1.size());
+ assertSame(_root, result1.get(0));
+
+ List<Node> result2 = xpath.evaluate(_root);
+ assertEquals(1, result2.size());
+ assertSame(_root, result2.get(0));
+
+ List<Node> result3 = xpath.evaluate(_child1);
+ assertEquals(1, result3.size());
+ assertSame(_child1, result3.get(0));
+ }
+
+
+ public void testEvalAsString()
+ throws Exception
+ {
+ _root.setAttribute("foo", "bar");
+ _root.setAttribute("argle", "bargle");
+
+ XPathWrapper xpath = new XPathWrapper("@foo");
+
+ assertEquals("bar", xpath.evaluateAsString(_root));
+ assertEquals("bar", xpath.evaluateAsString(_dom));
+ }
+
+
+ public void testEvalAsNumber()
+ throws Exception
+ {
+ _root.setAttribute("foo", "10");
+
+ XPathWrapper xpath = new XPathWrapper("@foo");
+
+ assertEquals(Double.valueOf(10.0), xpath.evaluateAsNumber(_root));
+ assertEquals(Double.valueOf(10.0), xpath.evaluateAsNumber(_dom));
+ }
+
+
+ public void testEvalAsBoolean()
+ throws Exception
+ {
+ _root.setAttribute("foo", "10");
+
+ XPathWrapper xpath1 = new XPathWrapper("@foo=10");
+
+ assertTrue(xpath1.evaluateAsBoolean(_root).booleanValue());
+ assertTrue(xpath1.evaluateAsBoolean(_dom).booleanValue());
+
+ _root.setAttribute("foo", "20");
+
+ assertFalse(xpath1.evaluateAsBoolean(_root).booleanValue());
+ assertFalse(xpath1.evaluateAsBoolean(_dom).booleanValue());
+ }
+
+
+ public void testNamespaces() throws Exception
+ {
+ XPathWrapper xpath1 = new XPathWrapper("//child");
+ List<Node> result1 = xpath1.evaluate(_dom);
+ assertEquals(1, result1.size());
+ assertSame(_child1, result1.get(0));
+
+ XPathWrapper xpath2 = new XPathWrapper("//ns:child")
+ .bindNamespace("ns", NS1);
+ List<Node> result2 = xpath2.evaluate(_dom);
+ assertEquals(1, result2.size());
+ assertSame(_child2, result2.get(0));
+
+ XPathWrapper xpath3 = new XPathWrapper("//:child")
+ .bindDefaultNamespace(NS2);
+ List<Node> result3 = xpath3.evaluate(_dom);
+ assertEquals(1, result3.size());
+ assertSame(_child3, result3.get(0));
+ }
+
+
+ public void testVariables() throws Exception
+ {
+ _child1.setAttribute("bar", "baz");
+ _child2.setAttribute("bar", "bargle");
+
+ XPathWrapper xpath = new XPathWrapper("//*[@bar=$test]")
+ .bindVariable(new QName("test"), "baz");
+
+ List<Node> result1 = xpath.evaluate(_dom);
+ assertEquals(1, result1.size());
+ assertSame(_child1, result1.get(0));
+
+ xpath.bindVariable("test", "bargle");
+
+ List<Node> result2 = xpath.evaluate(_dom);
+ assertEquals(1, result2.size());
+ assertSame(_child2, result2.get(0));
+ }
+
+
+ public void testAbstractFunctions() throws Exception
+ {
+ XPathWrapper xpath1 = new XPathWrapper("ns:myfunc(.)")
+ .bindNamespace("ns", NS1)
+ .bindFunction(new MyAbstractFunction(NS1, "myfunc"));
+
+ assertEquals("", xpath1.evaluateAsString(_child1));
+ assertEquals(NS1, xpath1.evaluateAsString(_child2));
+
+ XPathWrapper xpath2 = new XPathWrapper("ns:myfunc(.)")
+ .bindFunction(new MyAbstractFunction(NS1, "myfunc"), "ns");
+
+ assertEquals("", xpath2.evaluateAsString(_child1));
+ assertEquals(NS1, xpath2.evaluateAsString(_child2));
+ }
+
+
+ public void testStandardFunctions() throws Exception
+ {
+ XPathWrapper xpath1 = new XPathWrapper("ns:myfunc(.)")
+ .bindFunction(new QName(NS1, "myfunc", "ns"),
+ new MyStandardFunction());
+
+ assertEquals("", xpath1.evaluateAsString(_child1));
+ assertEquals(NS1, xpath1.evaluateAsString(_child2));
+
+ XPathWrapper xpath2 = new XPathWrapper("ns:myfunc(.,.)")
+ .bindFunction(new QName(NS2, "myfunc", "ns"),
+ new MyStandardFunction(),
+ 2);
+
+ assertEquals("", xpath2.evaluateAsString(_child1));
+ assertEquals(NS1, xpath2.evaluateAsString(_child2));
+ }
+
+
+ public void testUnresolvableFunction() throws Exception
+ {
+ // we call with two arguments, it only gets resolved for one
+ XPathWrapper xpath1 = new XPathWrapper("ns:myfunc(.,.)")
+ .bindFunction(new QName(NS2, "myfunc", "ns"),
+ new MyStandardFunction(),
+ 1);
+ try
+ {
+ xpath1.evaluateAsString(_child1);
+ fail("didn't throw even though arity was wrong");
+ }
+ catch (XmlException ee)
+ {
+ // success
+ }
+ }
+
+
+
+ public void testEqualsAndHashCode() throws Exception
+ {
+ Object obj1a = new XPathWrapper("//foo");
+ Object obj1b = new XPathWrapper("//foo");
+ Object obj2a = new XPathWrapper("//foo")
+ .bindDefaultNamespace("zippy");
+ Object obj2b = new XPathWrapper("//foo")
+ .bindDefaultNamespace("zippy");
+ Object obj3a = new XPathWrapper("//foo")
+ .bindNamespace("argle", "bargle");
+ Object obj3b = new XPathWrapper("//foo")
+ .bindNamespace("argle", "bargle");
+ Object obj4a = new XPathWrapper("//foo")
+ .bindVariable("argle", "bargle");
+ Object obj4b = new XPathWrapper("//foo")
+ .bindVariable("argle", "bargle");
+ Object obj5a = new XPathWrapper("//foo")
+ .bindFunction(new QName("foo"), null);
+ Object obj5b = new XPathWrapper("//foo")
+ .bindFunction(new QName("foo"), null);
+
+ assertFalse(obj1a.equals(null));
+ assertFalse(obj1a.equals(new Object()));
+
+ assertTrue(obj1a.equals(obj1b));
+ assertTrue(obj1b.equals(obj1a));
+ assertEquals(obj1a.hashCode(), obj1b.hashCode());
+
+ assertFalse(obj1a.equals(obj2a));
+ assertTrue(obj2a.equals(obj2b));
+ assertTrue(obj2b.equals(obj2a));
+ assertEquals(obj1a.hashCode(), obj2a.hashCode());
+ assertEquals(obj2a.hashCode(), obj2b.hashCode());
+
+ assertFalse(obj1a.equals(obj3a));
+ assertTrue(obj3a.equals(obj3b));
+ assertTrue(obj3b.equals(obj3a));
+ assertEquals(obj1a.hashCode(), obj3a.hashCode());
+ assertEquals(obj3a.hashCode(), obj3b.hashCode());
+
+ assertFalse(obj1a.equals(obj4a));
+ assertTrue(obj4a.equals(obj4b));
+ assertTrue(obj4b.equals(obj4a));
+ assertEquals(obj1a.hashCode(), obj4a.hashCode());
+ assertEquals(obj4a.hashCode(), obj4b.hashCode());
+
+ assertFalse(obj1a.equals(obj5a));
+ assertTrue(obj5a.equals(obj5b));
+ assertTrue(obj5b.equals(obj5a));
+ assertEquals(obj1a.hashCode(), obj5a.hashCode());
+ assertEquals(obj5a.hashCode(), obj5b.hashCode());
+ }
+
+
+ public void testToString() throws Exception
+ {
+ final String expr = "//foo";
+ assertEquals(expr, new XPathWrapper(expr).toString());
+ assertEquals(expr, new XPathWrapper(expr).bindNamespace("foo", "bar").toString());
+ }
+
+
+ public void testFailures() throws Exception
+ {
+ try
+ {
+ new XPathWrapper(".foo.").evaluate(_dom);
+ fail("compiled invalid expression");
+ }
+ catch (XmlException ee)
+ {
+ // success
+ }
+
+ try
+ {
+ new XPathWrapper("@foo=$bar").evaluate(_dom);
+ fail("evaluated expression with unbound variable");
+ }
+ catch (XmlException ee)
+ {
+ // success
+ }
+ }
+
+}
Modified: trunk/src/test/java/net/sf/practicalxml/xpath/function/TestLowercase.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/xpath/function/TestLowercase.java 2008-12-29 00:35:16 UTC (rev 63)
+++ trunk/src/test/java/net/sf/practicalxml/xpath/function/TestLowercase.java 2008-12-29 00:42:26 UTC (rev 64)
@@ -10,7 +10,7 @@
import net.sf.practicalxml.AbstractTestCase;
import net.sf.practicalxml.DomUtil;
-import net.sf.practicalxml.XPathWrapper;
+import net.sf.practicalxml.xpath.XPathWrapper;
public class TestLowercase
Modified: trunk/src/test/java/net/sf/practicalxml/xpath/function/TestUppercase.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/xpath/function/TestUppercase.java 2008-12-29 00:35:16 UTC (rev 63)
+++ trunk/src/test/java/net/sf/practicalxml/xpath/function/TestUppercase.java 2008-12-29 00:42:26 UTC (rev 64)
@@ -10,7 +10,7 @@
import net.sf.practicalxml.AbstractTestCase;
import net.sf.practicalxml.DomUtil;
-import net.sf.practicalxml.XPathWrapper;
+import net.sf.practicalxml.xpath.XPathWrapper;
public class TestUppercase
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-29 00:35:20
|
Revision: 63
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=63&view=rev
Author: kdgregory
Date: 2008-12-29 00:35:16 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
SchemaUtil: combineSchema() renamed, now returns Document[] not Schema
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java
trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java
Modified: trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java 2008-12-28 15:56:10 UTC (rev 62)
+++ trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java 2008-12-29 00:35:16 UTC (rev 63)
@@ -94,12 +94,33 @@
*/
public static Schema newSchema(SchemaFactory factory, InputSource... sources)
{
- Document[] parsed = parseSources(sources);
+ return newSchema(factory, parseSources(sources));
+ }
+
+
+ /**
+ * Compiles one or more DOM documents to produce a <code>Schema</code>
+ * object from the passed factory. This call is synchronized on the
+ * factory, which the JDK 1.5 docs describe as not threadsafe.
+ * <p>
+ * The caller is responsible for ordering the documents so that imported
+ * schemas appear first. This method is unable to combine sources from
+ * the same target namespace; see {@link #combineSchema combineSchema()}
+ * for explanation.
+ *
+ * @param factory Used to create the schema object.
+ * @param sources The source schema documents.
+ *
+ * @throws IllegalArgumentException if invoked without any sources.
+ * @throws XmlException if unable to compile the schema.
+ */
+ public static Schema newSchema(SchemaFactory factory, Document... sources)
+ {
try
{
synchronized (factory)
{
- return factory.newSchema(toDOMSources(parsed));
+ return factory.newSchema(toDOMSources(sources));
}
}
catch (SAXException e)
@@ -110,13 +131,14 @@
/**
- * Parses one or more input sources to produce a <code>Schema</code>
- * object. Unlike {@link #newSchema newSchema()}, this method will
- * combine source documents with the same target namespace (a workaround
- * for <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6198705">
- * JDK 1.5 bug 6198705</a>), order the source documents according to their
- * dependencies, and also remove external location references from <code>
- * <xsd:import></code> elements that reference provided sources.
+ * Parses and combines one or more input sources to produce an array
+ * of DOM documents containing schema components. Will properly order
+ * the output documents based on dependencies, remove any location
+ * references from imports that are satisfied by the sources, and
+ * provides a workaround for the
+ * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6198705">
+ * JDK 1.5 bug</a> that prevents combination of source documents with
+ * the same namespace.
* <p>
* When combining schema documents with the same namespace, all top-level
* attributes (eg, <code>elementFormDefault</code>) come from the first
@@ -129,9 +151,6 @@
* target namespace, any <code>schemaLocation</code> specification will
* be ignored.
*
- * @param factory Used to create the schema object. This factory's
- * <code>ErrorHandler</code> is also used to report
- * errors when parsing the source documents.
* @param sources The source schema documents. Note that these are
* <code>org.xml.sax.InputSource</code> objects for
* consistency with other classes in this library;
@@ -141,23 +160,12 @@
* @throws IllegalArgumentException if invoked without any sources, or if
* a source does not appear to be an XML Schema document (current
* checking is minimal, but that may change).
- * @throws XmlException on any failure that is not handled by the factory's
- * <code>ErrorHandler</code> (including parse errors).
+ * @throws XmlException on any parse error, or if the sources do not
+ * appear to be valid XSD documents.
*/
- public static Schema combineSchema(SchemaFactory factory, InputSource... sources)
+ public static Document[] combineSchemas(InputSource... sources)
{
- SchemaManager manager = new SchemaManager(parseSources(sources));
- try
- {
- synchronized (factory)
- {
- return factory.newSchema(manager.toDOMSources());
- }
- }
- catch (SAXException e)
- {
- throw new XmlException("unable to generate schema", e);
- }
+ return new SchemaManager(parseSources(sources)).buildOutput();
}
@@ -245,7 +253,7 @@
/**
* Returns the ordered set of sources for this manager.
*/
- public DOMSource[] toDOMSources()
+ public Document[] buildOutput()
{
TreeSet<Document> ordered = new TreeSet<Document>(new SchemaComparator());
for (Document doc : _documents.values())
@@ -253,7 +261,7 @@
ordered.add(rebuildImports(doc));
}
- return SchemaUtil.toDOMSources(ordered.toArray(new Document[ordered.size()]));
+ return ordered.toArray(new Document[ordered.size()]);
}
/**
Modified: trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java 2008-12-28 15:56:10 UTC (rev 62)
+++ trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java 2008-12-29 00:35:16 UTC (rev 63)
@@ -208,11 +208,12 @@
+ "<bargle>test</bargle>"
+ "</foo>";
- Schema schema = SchemaUtil.combineSchema(
+ Schema schema = SchemaUtil.newSchema(
SchemaUtil.newFactory(new ExceptionErrorHandler()),
- new InputSource(new StringReader(xsd1)),
- new InputSource(new StringReader(xsd2)),
- new InputSource(new StringReader(xsd3)));
+ SchemaUtil.combineSchemas(
+ new InputSource(new StringReader(xsd1)),
+ new InputSource(new StringReader(xsd2)),
+ new InputSource(new StringReader(xsd3))));
assertNotNull(schema);
ParseUtil.validatingParse(new InputSource(new StringReader(xml)),
@@ -245,10 +246,12 @@
+ "<argle>12</argle>"
+ "</foo>";
- Schema schema = SchemaUtil.combineSchema(
+
+ Schema schema = SchemaUtil.newSchema(
SchemaUtil.newFactory(new ExceptionErrorHandler()),
- new InputSource(new StringReader(xsd1)),
- new InputSource(new StringReader(xsd2)));
+ SchemaUtil.combineSchemas(
+ new InputSource(new StringReader(xsd1)),
+ new InputSource(new StringReader(xsd2))));
assertNotNull(schema);
ParseUtil.validatingParse(new InputSource(new StringReader(xml)),
@@ -296,11 +299,13 @@
+ "</foo>";
// note: these sources are intentionally out-of-order
- Schema schema = SchemaUtil.combineSchema(
+
+ Schema schema = SchemaUtil.newSchema(
SchemaUtil.newFactory(new ExceptionErrorHandler()),
- new InputSource(new StringReader(xsd1)),
- new InputSource(new StringReader(xsd2)),
- new InputSource(new StringReader(xsd3)));
+ SchemaUtil.combineSchemas(
+ new InputSource(new StringReader(xsd1)),
+ new InputSource(new StringReader(xsd2)),
+ new InputSource(new StringReader(xsd3))));
assertNotNull(schema);
ParseUtil.validatingParse(new InputSource(new StringReader(xml)),
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-28 15:56:13
|
Revision: 62
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=62&view=rev
Author: kdgregory
Date: 2008-12-28 15:56:10 +0000 (Sun, 28 Dec 2008)
Log Message:
-----------
Bug 2417477: SchemaUtil.newSchema() is for simple case, combineSchema() for bug workaround and ordering
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java
trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java
Modified: trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java 2008-12-28 00:46:35 UTC (rev 61)
+++ trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java 2008-12-28 15:56:10 UTC (rev 62)
@@ -1,5 +1,9 @@
package net.sf.practicalxml;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeSet;
import javax.xml.XMLConstants;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
@@ -11,7 +15,7 @@
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
-import org.apache.commons.lang.StringUtils;
+import net.sf.practicalxml.util.ExceptionErrorHandler;
/**
@@ -19,54 +23,15 @@
* documents. Since <code>javax.xml.validation.Schema</code> is an
* opaque object, most of these actually work with DOM documents that
* contain an XSD.
- * <p>
- * <b>Behavior of {@link #newSchema newSchema()} and {@link
- * #newSchemas newSchemas()}</b>
- * <p>
- * These methods exist to create a {@link javax.xml.validation.Schema}
- * from an XML source. Their basic behavior is to hide the underlying
- * factory objects, similar to {@link ParseUtil} and {@link OutputUtil}.
- * However, also they support the creation of <code>Schema<code> objects
- * from multiple sources, and in this have to deal with a
- * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6198705">
- * bug in the JDK</a> (and also in
- * <a href="http://issues.apache.org/jira/browse/XERCESJ-1130">Xerces</a>)
- * that prevents the combination of schema documents that specify the same
- * namespace (this also prevents <xs:import> from working).
- * <p>
- * Combining schema documents isn't an easy task, which is probably why the
- * bug still isn't fixed. The top-level attributes (those attached to the
- * <code><xs:schema></code> element) are the main problem, as they have
- * to be consistent across the component schema docs. The approach used by
- * {@link #newSchema newSchema()} is to take these attributes from the first
- * source (for {@link #newSchemas newSchemas()}, the first source for a given
- * namespace URI), and apply the following rules:
- * <ul>
- * <li><code>targetNamespace</code>
- * <br>This must be the same for all source documents processed by {@link
- * #newSchema newSchema()}; if not, it throws an exception. By comparison,
- * {@link #newSchemas newSchemas()} will partition source documents by
- * their value, so an incorrect source document will be silently assigned
- * its own <code>Schema</code> object.
- * <li><code>attributeFormDefault</code>, <code>elementFormDefault</code>
- * <br>The first source document defines these attributes for the resulting
- * <code>Schema</code> object. If later sources define different values,
- * those values are ignored. This behavior largely reflects my view of
- * how an XSD should be modularized (with a single <code>xsd:element
- * </code> in the first source, type definitions in subsequent sources),
- * but it is also driven by consistency in instance documents. As a side
- * note, I strongly recommend that <code>elementFormDefault</code> be
- * "qualified", as that allows the use of a default namespace in instance
- * documents.
- * <li>all other attributes
- * <br>Are defined by the first source, and ignored on any subsequent sources.
- * </ul>
*/
public class SchemaUtil
{
- private final static String SCHEMA_NS = XMLConstants.W3C_XML_SCHEMA_NS_URI;
+ private final static String NS_SCHEMA = XMLConstants.W3C_XML_SCHEMA_NS_URI;
private final static String EL_SCHEMA = "schema";
+ private final static String EL_IMPORT = "import";
private final static String ATTR_TARGET_NS = "targetNamespace";
+ private final static String ATTR_IMPORT_NS = "namespace";
+ private final static String ATTR_IMPORT_LOC = "schemaLocation";
/**
@@ -83,34 +48,116 @@
/**
- * Parses the passed input sources to produce a single <code>Schema</code>
- * object. All sources must have the same <code>targetNamespace</code>;
- * other top-level attributes will be taken from the first source.
+ * Parses one or more input sources to produce a <code>Schema</code>
+ * object. Validators produced from this schema will throw an
+ * {@link XmlException} on any error.
+ * <p>
+ * The caller is responsible for ordering the sources so that imported
+ * schemas appear first. This method is unable to combine sources from
+ * the same target namespace; see {@link #combineSchema combineSchema()}
+ * for explanation.
*
+ * @param sources The source schema documents. Note that these are
+ * <code>org.xml.sax.InputSource</code> objects for
+ * consistency with other classes in this library;
+ * not the <code>javax.xml.transform.Source</code>
+ * objects used by <code>SchemaFactory</code>.
+ *
+ * @throws IllegalArgumentException if invoked without any sources.
+ * @throws XmlException if unable to create the schema object.
+ */
+ public static Schema newSchema(InputSource... sources)
+ {
+ return newSchema(newFactory(new ExceptionErrorHandler()), sources);
+ }
+
+
+ /**
+ * Parses one or more input sources to produce a <code>Schema</code>
+ * object from the passed factory. This call is synchronized on the
+ * factory, which the JDK 1.5 docs describe as not threadsafe.
+ * <p>
+ * The caller is responsible for ordering the sources so that imported
+ * schemas appear first. This method is unable to combine sources from
+ * the same target namespace; see {@link #combineSchema combineSchema()}
+ * for explanation.
+ *
+ * @param factory Used to create the schema object.
+ * @param sources The source schema documents. Note that these are
+ * <code>org.xml.sax.InputSource</code> objects for
+ * consistency with other classes in this library;
+ * not the <code>javax.xml.transform.Source</code>
+ * objects used by <code>SchemaFactory</code>.
+ *
+ * @throws IllegalArgumentException if invoked without any sources.
+ * @throws XmlException if unable to parse a source or compile the schema.
+ */
+ public static Schema newSchema(SchemaFactory factory, InputSource... sources)
+ {
+ Document[] parsed = parseSources(sources);
+ try
+ {
+ synchronized (factory)
+ {
+ return factory.newSchema(toDOMSources(parsed));
+ }
+ }
+ catch (SAXException e)
+ {
+ throw new XmlException("unable to generate schema", e);
+ }
+ }
+
+
+ /**
+ * Parses one or more input sources to produce a <code>Schema</code>
+ * object. Unlike {@link #newSchema newSchema()}, this method will
+ * combine source documents with the same target namespace (a workaround
+ * for <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6198705">
+ * JDK 1.5 bug 6198705</a>), order the source documents according to their
+ * dependencies, and also remove external location references from <code>
+ * <xsd:import></code> elements that reference provided sources.
+ * <p>
+ * When combining schema documents with the same namespace, all top-level
+ * attributes (eg, <code>elementFormDefault</code>) come from the first
+ * source specified for the namespace. The <code><xsd:schema></code>
+ * element, and its attributes, are ignored for subsequent sources for
+ * that namespace.
+ * <p>
+ * Sources must contain <code><xsd:import></code> elements for any
+ * referenced schemas. If the sources contain a schema for the specified
+ * target namespace, any <code>schemaLocation</code> specification will
+ * be ignored.
+ *
* @param factory Used to create the schema object. This factory's
* <code>ErrorHandler</code> is also used to report
* errors when parsing the source documents.
- * @param sources The source schema documents.
+ * @param sources The source schema documents. Note that these are
+ * <code>org.xml.sax.InputSource</code> objects for
+ * consistency with other classes in this library;
+ * not the <code>javax.xml.transform.Source</code>
+ * objects used by <code>SchemaFactory</code>.
*
* @throws IllegalArgumentException if invoked without any sources, or if
- * a source does not have the target namespace established by the
- * first source.
- * @throws XmlException if the sources are not combinable, or on any
- * failure that is not handled by the factory's <code>ErrorHandler
- * </code> (including parse errors and local validation of the
- * source root element).
+ * a source does not appear to be an XML Schema document (current
+ * checking is minimal, but that may change).
+ * @throws XmlException on any failure that is not handled by the factory's
+ * <code>ErrorHandler</code> (including parse errors).
*/
- public static Schema newSchema(SchemaFactory factory, InputSource... sources)
+ public static Schema combineSchema(SchemaFactory factory, InputSource... sources)
{
- if (sources.length == 0)
- throw new IllegalArgumentException("must specify at least one source");
-
- Document dom = parse(sources[0]);
- for (int ii = 1 ; ii < sources.length ; ii++)
+ SchemaManager manager = new SchemaManager(parseSources(sources));
+ try
{
- combine(dom, parse(sources[ii]));
+ synchronized (factory)
+ {
+ return factory.newSchema(manager.toDOMSources());
+ }
}
- return generate(factory, dom);
+ catch (SAXException e)
+ {
+ throw new XmlException("unable to generate schema", e);
+ }
}
@@ -119,65 +166,190 @@
//----------------------------------------------------------------------------
/**
- * Parses an XML document and performs some perfunctory checks to verify
- * that it's an XML schema. Perhaps in the future we'll add a "validation
- * level" property that at high levels validates against the "Schema for
- * Schemas"
+ * Parses an array of <code>org.xml.sax.InputSource</code> objects, and
+ * performs some (minimal) level of validation on them. This method is
+ * called by <code>newSchema()</code> and <code>combineSchema()</code>,
+ * and will identify the source that wasn't valid.
+ *
+ * @throws IllegalArgumentException if no sources specified (this is
+ * a common check for callers).
*/
- private static Document parse(InputSource source)
+ public static Document[] parseSources(InputSource[] sources)
{
- Document dom = ParseUtil.parse(source);
- Element root = dom.getDocumentElement();
- if (!DomUtil.isNamed(root, SCHEMA_NS, EL_SCHEMA))
+ if (sources.length == 0)
+ throw new IllegalArgumentException("must specify at least one source");
+
+ Document[] result = new Document[sources.length];
+ for (int ii = 0 ; ii < sources.length ; ii++)
{
- throw new XmlException("invalid root element name: {"
- + root.getNamespaceURI() + "}"
- + DomUtil.getLocalName(root));
+ try
+ {
+ result[ii] = ParseUtil.parse(sources[ii]);
+ }
+ catch (XmlException ee)
+ {
+ throw new XmlException("unable to parse source " + ii, ee.getCause());
+ }
}
- return dom;
+
+ for (int ii = 0 ; ii < result.length ; ii++)
+ {
+ if (!DomUtil.isNamed(result[ii].getDocumentElement(), NS_SCHEMA, EL_SCHEMA))
+ throw new XmlException("source " + ii + " does not appear to be an XSD");
+ }
+
+ return result;
}
+ /**
+ * Wraps an array of DOM documents so that they can be processed by
+ * <code>SchemaFactory</code>.
+ */
+ private static DOMSource[] toDOMSources(Document[] sources)
+ {
+ DOMSource[] result = new DOMSource[sources.length];
+ for (int ii = 0 ; ii < sources.length ; ii++)
+ {
+ result[ii] = new DOMSource(sources[ii]);
+ }
+ return result;
+ }
+
/**
- * Merges the second DOM object into the first, verifying that it (1)
- * claims to be an XML Schema, and (2) has the same root attributes as
- * the first document.
+ * This object is the brains behind {@link #combineSchema}. It is
+ * currently written for the quirks of the 1.5 JDK; if those quirks
+ * are different under 1.6, it will be moved into its own package and
+ * accessed via a factory.
+ * <p>
+ * Defined as protected -- as are internal methods -- so that it can be
+ * tested independently.
*/
- private static void combine(Document dst, Document src)
+ protected static class SchemaManager
{
- Element srcRoot = src.getDocumentElement();
- Element dstRoot = dst.getDocumentElement();
+ private HashMap<String,Document> _documents = new HashMap<String,Document>();
- String srcTargetNS = srcRoot.getAttribute(ATTR_TARGET_NS);
- String dstTargetNS = dstRoot.getAttribute(ATTR_TARGET_NS);
- if (!StringUtils.equals(srcTargetNS, dstTargetNS))
- throw new IllegalArgumentException(
- "cannot combine target namespaces: expected "
- + "\"" + dstTargetNS + "\", was \"" + srcTargetNS + "\"");
+ public SchemaManager(Document[] sources)
+ {
+ for (int ii = 0 ; ii < sources.length ; ii++)
+ {
+ String srcNamespace = sources[ii].getDocumentElement().getAttribute(ATTR_TARGET_NS);
+ Document existing = _documents.get(srcNamespace);
+ if (existing != null)
+ merge(existing, sources[ii]);
+ else
+ _documents.put(srcNamespace, sources[ii]);
+ }
+ }
- for (Element child : DomUtil.getChildren(srcRoot))
+ /**
+ * Returns the ordered set of sources for this manager.
+ */
+ public DOMSource[] toDOMSources()
{
- Node tmp = dst.importNode(child, true);
- dstRoot.appendChild(tmp);
+ TreeSet<Document> ordered = new TreeSet<Document>(new SchemaComparator());
+ for (Document doc : _documents.values())
+ {
+ ordered.add(rebuildImports(doc));
+ }
+
+ return SchemaUtil.toDOMSources(ordered.toArray(new Document[ordered.size()]));
}
+
+ /**
+ * Merges one schema document into another.
+ */
+ protected void merge(Document dst, Document src)
+ {
+ Element dstRoot = dst.getDocumentElement();
+ Element srcRoot = src.getDocumentElement();
+ for (Element child : DomUtil.getChildren(srcRoot))
+ {
+ Node tmp = dst.importNode(child, true);
+ dstRoot.appendChild(tmp);
+ }
+ }
+
+ /**
+ * Rebuilds the <code>import</code> statements for the passed
+ * document, removing duplicates and clearing locations for
+ * namespaces that are known to this manager. Returns the
+ * cleaned document.
+ */
+ protected Document rebuildImports(Document doc)
+ {
+ Map<String,String> imports = new HashMap<String,String>();
+ Element root = doc.getDocumentElement();
+ for (Element imp : DomUtil.getChildren(root, NS_SCHEMA, EL_IMPORT))
+ {
+ String namespace = imp.getAttribute(ATTR_IMPORT_NS);
+ String location = imp.getAttribute(ATTR_IMPORT_LOC);
+ if (_documents.containsKey(namespace))
+ location = null;
+ imports.put(namespace, location);
+ root.removeChild(imp);
+ }
+
+ for (String namespace : imports.keySet())
+ {
+ String location = imports.get(namespace);
+ Element newImport = doc.createElementNS(NS_SCHEMA, EL_IMPORT);
+ newImport.setAttribute(ATTR_IMPORT_NS, namespace);
+ if (location != null)
+ newImport.setAttribute(ATTR_IMPORT_LOC, location);
+ root.insertBefore(newImport, root.getFirstChild());
+ }
+ return doc;
+ }
}
/**
- * Generates a new <code>Schema</code> object from a DOM document.
+ * Compares two schema documents: one schema is greater-than another if
+ * it imports the other's namespace. To impose a total ordering, schemas
+ * that don't have interdependencies are ordered based on their target
+ * namespace URLs, and schemas with no target namespace are greater-than
+ * those with (since they cannot be imported).
+ * <p>
+ * Defined as protected so that it can be tested independently.
*/
- private static Schema generate(SchemaFactory factory, Document dom)
+ protected static class SchemaComparator
+ implements Comparator<Document>
{
- try
+ public int compare(Document o1, Document o2)
{
- synchronized (factory)
+ if (o1 == o2)
+ return 0;
+
+ Element root1 = o1.getDocumentElement();
+ String namespace1 = root1.getAttribute(ATTR_TARGET_NS);
+
+ Element root2 = o2.getDocumentElement();
+ String namespace2 = root2.getAttribute(ATTR_TARGET_NS);
+
+ if (namespace1.equals(namespace2))
+ return 0;
+ else if ("".equals(namespace1))
+ return 1;
+ else if ("".equals(namespace2))
+ return -1;
+
+ if (isImportedBy(namespace1, root2))
+ return -1;
+ else if (isImportedBy(namespace2, root1))
+ return 1;
+
+ return namespace1.compareTo(namespace2);
+ }
+
+ private boolean isImportedBy(String namespace, Element root)
+ {
+ for (Element imp : DomUtil.getChildren(root, NS_SCHEMA, EL_IMPORT))
{
- return factory.newSchema(new DOMSource(dom));
+ if (namespace.equals(imp.getAttribute(ATTR_IMPORT_NS)))
+ return true;
}
+ return false;
}
- catch (SAXException e)
- {
- throw new XmlException("unable to generate schema", e);
- }
}
}
Modified: trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java 2008-12-28 00:46:35 UTC (rev 61)
+++ trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java 2008-12-28 15:56:10 UTC (rev 62)
@@ -1,12 +1,17 @@
package net.sf.practicalxml;
import java.io.StringReader;
+import java.util.Comparator;
+import java.util.List;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
+import net.sf.practicalxml.SchemaUtil.SchemaManager;
import net.sf.practicalxml.util.ExceptionErrorHandler;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
@@ -15,13 +20,7 @@
extends AbstractTestCase
{
//----------------------------------------------------------------------------
-// Support Code
-//----------------------------------------------------------------------------
-
-
-
-//----------------------------------------------------------------------------
-// Test Cases
+// Test Cases for public methods
//
// Note: since we can't examine a schema once it's compiled, we need to
// verify newSchema() operation with actual instance docs ... and
@@ -61,9 +60,57 @@
+ "<bargle>test</bargle>"
+ "</foo>";
+ Schema schema = SchemaUtil.newSchema(new InputSource(new StringReader(xsd)));
+
+ assertNotNull(schema);
+ ParseUtil.validatingParse(new InputSource(new StringReader(xml)),
+ schema,
+ new ExceptionErrorHandler());
+ }
+
+
+ public void testNewSchemaMultipleNamepaces() throws Exception
+ {
+ String xsd1 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://foo.example.com'"
+ + " xmlns:bar='http://bar.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:import namespace='http://bar.example.com'/>"
+ + "<xsd:element name='foo' type='bar:FooType'/>"
+ + "</xsd:schema>";
+ String xsd2 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://bar.example.com'"
+ + " xmlns:baz='http://baz.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:import namespace='http://baz.example.com'/>"
+ + "<xsd:complexType name='FooType'>"
+ + "<xsd:sequence>"
+ + "<xsd:element name='argle' type='xsd:integer'/>"
+ + "<xsd:element name='bargle' type='baz:BarType'/>"
+ + "</xsd:sequence>"
+ + "</xsd:complexType>"
+ + "</xsd:schema>";
+ String xsd3 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://baz.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:simpleType name='BarType'>"
+ + "<xsd:restriction base='xsd:string'>"
+ + "</xsd:restriction>"
+ + "</xsd:simpleType>"
+ + "</xsd:schema>";
+
+ String xml = "<foo xmlns='http://foo.example.com'>"
+ + "<argle xmlns='http://bar.example.com'>12</argle>"
+ + "<bargle xmlns='http://bar.example.com'>12</bargle>"
+ + "</foo>";
+
Schema schema = SchemaUtil.newSchema(
- SchemaUtil.newFactory(new ExceptionErrorHandler()),
- new InputSource(new StringReader(xsd)));
+ new InputSource(new StringReader(xsd3)),
+ new InputSource(new StringReader(xsd2)),
+ new InputSource(new StringReader(xsd1)));
assertNotNull(schema);
ParseUtil.validatingParse(new InputSource(new StringReader(xml)),
@@ -72,8 +119,72 @@
}
- public void testNewSchemaMultipleSources() throws Exception
+ public void testNewSchemaFailNoSources() throws Exception
{
+ try
+ {
+ SchemaUtil.newSchema();
+ fail("no sources, no exception");
+ }
+ catch (IllegalArgumentException ee)
+ {
+ // success
+ }
+ }
+
+
+ public void testNewSchemaFailInvalidDocument() throws Exception
+ {
+ // looks right, but no namespace definition
+ String xsd = "<schema>"
+ + "<element name='foo' type='FooType'/>"
+ + "<complexType name='FooType'>"
+ + "<sequence>"
+ + "<element name='argle' type='xsd:integer'/>"
+ + "</sequence>"
+ + "</complexType>"
+ + "</schema>";
+
+ try
+ {
+ SchemaUtil.newSchema(new InputSource(new StringReader(xsd)));
+ fail("created schema from an invalid document");
+ }
+ catch (XmlException ee)
+ {
+ assertTrue(ee.getMessage().contains("source 0"));
+ }
+ }
+
+
+ public void testNewSchemaFailUnparsableSource() throws Exception
+ {
+ String xsd1 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://foo.example.com'"
+ + " xmlns:bar='http://bar.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:import namespace='http://bar.example.com'/>"
+ + "<xsd:element name='foo' type='bar:FooType'/>"
+ + "</xsd:schema>";
+ String xsd2 = "this isn't XML";
+
+ try
+ {
+ SchemaUtil.newSchema(
+ new InputSource(new StringReader(xsd1)),
+ new InputSource(new StringReader(xsd2)));
+ fail("parsed an invalid XML document");
+ }
+ catch (XmlException ee)
+ {
+ assertTrue(ee.getMessage().contains("source 1"));
+ }
+ }
+
+
+ public void testCombineSchemaMultipleSourceNoNamespace() throws Exception
+ {
String xsd1 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'>"
+ "<xsd:element name='foo' type='FooType'/>"
+ "</xsd:schema>";
@@ -97,7 +208,7 @@
+ "<bargle>test</bargle>"
+ "</foo>";
- Schema schema = SchemaUtil.newSchema(
+ Schema schema = SchemaUtil.combineSchema(
SchemaUtil.newFactory(new ExceptionErrorHandler()),
new InputSource(new StringReader(xsd1)),
new InputSource(new StringReader(xsd2)),
@@ -110,28 +221,34 @@
}
- public void testNewSchemaSingleSourceWithNamespace() throws Exception
+ public void testCombineSchemaMultipleSourceSingleNamespace() throws Exception
{
- String xsd = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
- + " xmlns='http://foo.example.com'"
- + " targetNamespace='http://foo.example.com'"
- + " elementFormDefault='qualified'"
- + ">"
- + "<xsd:element name='foo' type='FooType'/>"
- + "<xsd:complexType name='FooType'>"
- + "<xsd:sequence>"
- + "<xsd:element name='argle' type='xsd:integer'/>"
- + "</xsd:sequence>"
- + "</xsd:complexType>"
- + "</xsd:schema>";
+ String xsd1 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " xmlns='http://foo.example.com'"
+ + " targetNamespace='http://foo.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:element name='foo' type='FooType'/>"
+ + "</xsd:schema>";
+ String xsd2 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://foo.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:complexType name='FooType'>"
+ + "<xsd:sequence>"
+ + "<xsd:element name='argle' type='xsd:integer'/>"
+ + "</xsd:sequence>"
+ + "</xsd:complexType>"
+ + "</xsd:schema>";
String xml = "<foo xmlns='http://foo.example.com'>"
+ "<argle>12</argle>"
+ "</foo>";
- Schema schema = SchemaUtil.newSchema(
+ Schema schema = SchemaUtil.combineSchema(
SchemaUtil.newFactory(new ExceptionErrorHandler()),
- new InputSource(new StringReader(xsd)));
+ new InputSource(new StringReader(xsd1)),
+ new InputSource(new StringReader(xsd2)));
assertNotNull(schema);
ParseUtil.validatingParse(new InputSource(new StringReader(xml)),
@@ -140,34 +257,50 @@
}
- public void testNewSchemaMultipleSourceWithNamespace() throws Exception
+ public void testCombineSchemaMultipleSourceMultipleNamepaces() throws Exception
{
String xsd1 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
- + " xmlns='http://foo.example.com'"
+ " targetNamespace='http://foo.example.com'"
+ + " xmlns:bar='http://bar.example.com'"
+ " elementFormDefault='qualified'"
+ ">"
- + "<xsd:element name='foo' type='FooType'/>"
+ + "<xsd:import namespace='http://bar.example.com'/>"
+ + "<xsd:element name='foo' type='bar:FooType'/>"
+ "</xsd:schema>";
String xsd2 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
- + " targetNamespace='http://foo.example.com'"
+ + " targetNamespace='http://bar.example.com'"
+ + " xmlns:baz='http://baz.example.com'"
+ " elementFormDefault='qualified'"
+ ">"
+ + "<xsd:import namespace='http://baz.example.com'/>"
+ "<xsd:complexType name='FooType'>"
+ "<xsd:sequence>"
- + "<xsd:element name='argle' type='xsd:integer'/>"
+ + "<xsd:element name='argle' type='xsd:integer'/>"
+ + "<xsd:element name='bargle' type='baz:BarType'/>"
+ "</xsd:sequence>"
+ "</xsd:complexType>"
+ "</xsd:schema>";
+ String xsd3 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://baz.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:simpleType name='BarType'>"
+ + "<xsd:restriction base='xsd:string'>"
+ + "</xsd:restriction>"
+ + "</xsd:simpleType>"
+ + "</xsd:schema>";
String xml = "<foo xmlns='http://foo.example.com'>"
- + "<argle>12</argle>"
+ + "<argle xmlns='http://bar.example.com'>12</argle>"
+ + "<bargle xmlns='http://bar.example.com'>12</bargle>"
+ "</foo>";
- Schema schema = SchemaUtil.newSchema(
+ // note: these sources are intentionally out-of-order
+ Schema schema = SchemaUtil.combineSchema(
SchemaUtil.newFactory(new ExceptionErrorHandler()),
new InputSource(new StringReader(xsd1)),
- new InputSource(new StringReader(xsd2)));
+ new InputSource(new StringReader(xsd2)),
+ new InputSource(new StringReader(xsd3)));
assertNotNull(schema);
ParseUtil.validatingParse(new InputSource(new StringReader(xml)),
@@ -176,37 +309,160 @@
}
- public void testNewSchemaFailMultipleNamepaces() throws Exception
+//----------------------------------------------------------------------------
+// Test cases for internals
+//----------------------------------------------------------------------------
+
+ public void testSchemaManagerMerge() throws Exception
{
- String xsd1 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
- + " xmlns:foo='http://foo.example.com'"
+ Document[] docs = new Document[]
+ {
+ ParseUtil.parse(
+ "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ " targetNamespace='http://foo.example.com'"
+ + ">"
+ + "<xsd:import namespace='http://bar.example.com'"
+ + " schemaLocation='http://bar.example.com'/>"
+ + "<xsd:element name='foo' type='bar:FooType'/>"
+ + "</xsd:schema>"),
+ ParseUtil.parse(
+ "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://foo.example.com'"
+ + ">"
+ + "<xsd:complexType name='FooType'>"
+ + "<xsd:sequence>"
+ + "<xsd:element name='argle' type='xsd:integer'/>"
+ + "</xsd:sequence>"
+ + "</xsd:complexType>"
+ + "</xsd:schema>")
+ };
+
+ Element doc0Root = docs[0].getDocumentElement();
+ List<Element> childrenBeforeManagement = DomUtil.getChildren(doc0Root);
+ assertEquals(2, childrenBeforeManagement.size());
+
+ new SchemaUtil.SchemaManager(docs);
+ List<Element> childrenAfterManagement = DomUtil.getChildren(doc0Root);
+ assertEquals(3, childrenAfterManagement.size());
+ }
+
+
+ public void testSchemaManagerImportRebuild() throws Exception
+ {
+ Document[] docs = new Document[]
+ {
+ ParseUtil.parse(
+ "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://foo.example.com'"
+ + ">"
+ + "<xsd:import namespace='http://bar.example.com'"
+ + " schemaLocation='http://bar.example.com'/>"
+ + "<xsd:element name='foo' type='bar:FooType'/>"
+ + "</xsd:schema>"),
+ ParseUtil.parse(
+ "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://bar.example.com'"
+ + ">"
+ + "<xsd:complexType name='FooType'>"
+ + "<xsd:sequence>"
+ + "<xsd:element name='argle' type='xsd:integer'/>"
+ + "</xsd:sequence>"
+ + "</xsd:complexType>"
+ + "</xsd:schema>")
+ };
+ SchemaManager manager = new SchemaUtil.SchemaManager(docs);
+
+ Document rebuilt = manager.rebuildImports(docs[0]);
+ List<Element> imports = DomUtil.getChildren(
+ rebuilt.getDocumentElement(),
+ "http://www.w3.org/2001/XMLSchema",
+ "import");
+ assertEquals(1, imports.size());
+
+ Element imp = imports.get(0);
+ assertEquals("http://bar.example.com", imp.getAttribute("namespace"));
+ assertEquals("", imp.getAttribute("schemaLocation"));
+ }
+
+
+ public void testSchemaComparator() throws Exception
+ {
+ Document doc1 = ParseUtil.parse(
+ "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://foo.example.com'"
+ " elementFormDefault='qualified'"
+ ">"
- + "<xsd:element name='foo' type='foo:FooType'/>"
- + "</xsd:schema>";
- String xsd2 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + "<xsd:import namespace='http://bar.example.com'/>"
+ + "<xsd:element name='foo' type='bar:FooType'/>"
+ + "</xsd:schema>");
+ Document doc1b = ParseUtil.parse(
+ "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://foo.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:import namespace='http://bar.example.com'/>"
+ + "<xsd:element name='foo' type='bar:FooType'/>"
+ + "</xsd:schema>");
+ Document doc2 = ParseUtil.parse(
+ "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ " targetNamespace='http://bar.example.com'"
+ + " xmlns:baz='http://bar.example.com'"
+ " elementFormDefault='qualified'"
+ ">"
+ + "<xsd:import namespace='http://baz.example.com'/>"
+ "<xsd:complexType name='FooType'>"
+ "<xsd:sequence>"
+ "<xsd:element name='argle' type='xsd:integer'/>"
+ + "<xsd:element name='bargle' type='baz:BarType'/>"
+ "</xsd:sequence>"
+ "</xsd:complexType>"
- + "</xsd:schema>";
+ + "</xsd:schema>");
+ Document doc3 = ParseUtil.parse(
+ "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://baz.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:simpleType name='BarType'>"
+ + "<xsd:restriction base='xsd:string'>"
+ + "</xsd:restriction>"
+ + "</xsd:simpleType>"
+ + "</xsd:schema>");
+ Document doc4 = ParseUtil.parse(
+ "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:simpleType name='ZippyType'>"
+ + "<xsd:restriction base='xsd:string'>"
+ + "</xsd:restriction>"
+ + "</xsd:simpleType>"
+ + "</xsd:schema>");
+ Document doc4b = ParseUtil.parse(
+ "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:simpleType name='ZippyType'>"
+ + "<xsd:restriction base='xsd:string'>"
+ + "</xsd:restriction>"
+ + "</xsd:simpleType>"
+ + "</xsd:schema>");
- try
- {
- SchemaUtil.newSchema(
- SchemaUtil.newFactory(new ExceptionErrorHandler()),
- new InputSource(new StringReader(xsd1)),
- new InputSource(new StringReader(xsd2)));
- fail("combined schemas with different target namespaces");
- }
- catch (IllegalArgumentException ee)
- {
- // success
- }
+ Comparator<Document> comparator = new SchemaUtil.SchemaComparator();
+
+ // import relationship
+ assertTrue(comparator.compare(doc1, doc2) > 0);
+ assertTrue(comparator.compare(doc2, doc1) < 0);
+
+ // target namespace
+ assertTrue(comparator.compare(doc1, doc3) > 0);
+ assertTrue(comparator.compare(doc3, doc1) < 0);
+
+ // target namespace versus none
+ assertTrue(comparator.compare(doc1, doc4) < 0);
+ assertTrue(comparator.compare(doc4, doc1) > 0);
+
+ // equality
+ assertTrue(comparator.compare(doc1, doc1) == 0);
+ assertTrue(comparator.compare(doc1, doc1b) == 0);
+ assertTrue(comparator.compare(doc4, doc4b) == 0);
}
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-28 00:46:56
|
Revision: 61
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=61&view=rev
Author: kdgregory
Date: 2008-12-28 00:46:35 +0000 (Sun, 28 Dec 2008)
Log Message:
-----------
OutputUtil: add elementToString(), treeToString()
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/OutputUtil.java
trunk/src/test/java/net/sf/practicalxml/TestOutputUtil.java
Modified: trunk/src/main/java/net/sf/practicalxml/OutputUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/OutputUtil.java 2008-12-24 00:31:26 UTC (rev 60)
+++ trunk/src/main/java/net/sf/practicalxml/OutputUtil.java 2008-12-28 00:46:35 UTC (rev 61)
@@ -14,6 +14,7 @@
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
+import org.w3c.dom.Element;
/**
@@ -25,6 +26,31 @@
public class OutputUtil
{
/**
+ * A simple <code>toString()</code> for an element, using the format
+ * "<code>{<i>NSURI</i>}<i>LOCALNAME</i></code>"; if the element has no
+ * namespace, the brackets remain but are empty.
+ */
+ public static String elementToString(Element elem)
+ {
+ return appendElementString(new StringBuilder(256), elem).toString();
+ }
+
+
+ /**
+ * Debug dump of the tree rooted at the specified element. Each line holds
+ * one element,
+ *
+ *
+ * @param elem
+ * @param indent
+ */
+ public static String treeToString(Element elem, int indent)
+ {
+ return appendTreeString(new StringBuilder(1024), elem, indent, 0).toString();
+ }
+
+
+ /**
* Writes a DOM document to a simple string format, without a prologue or
* whitespace between elements.
* <p>
@@ -206,6 +232,41 @@
//----------------------------------------------------------------------------
/**
+ * The actual implementation of {@link #elementToString}, which appends
+ * the string format to a passed buffer. Returns the buffer as a
+ * convenience.
+ */
+ private static StringBuilder appendElementString(StringBuilder buf, Element elem)
+ {
+ String namespaceURI = elem.getNamespaceURI();
+ String localName = DomUtil.getLocalName(elem);
+
+ return buf.append("{")
+ .append((namespaceURI != null) ? namespaceURI : "")
+ .append("}")
+ .append(localName);
+ }
+
+ /**
+ * Actual implementation of <code>dumpTree</code>, using a passed buffer
+ * so that we're not doing lots of string concats
+ */
+ private static StringBuilder appendTreeString(StringBuilder buf, Element elem, int indent, int curIndent)
+ {
+ if (buf.length() > 0)
+ buf.append("\n");
+ for (int ii = 0 ; ii < curIndent ; ii++)
+ buf.append(" ");
+ appendElementString(buf, elem);
+ for (Element child : DomUtil.getChildren(elem))
+ {
+ appendTreeString(buf, child, indent, curIndent + indent);
+ }
+ return buf;
+ }
+
+
+ /**
* Flushes an <code>OutputStream</code>, wrapping exceptions.
*/
private static void flushStream(OutputStream stream)
Modified: trunk/src/test/java/net/sf/practicalxml/TestOutputUtil.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestOutputUtil.java 2008-12-24 00:31:26 UTC (rev 60)
+++ trunk/src/test/java/net/sf/practicalxml/TestOutputUtil.java 2008-12-28 00:46:35 UTC (rev 61)
@@ -31,10 +31,30 @@
//----------------------------------------------------------------------------
-// Test Cases -- we're looking for overall structure, assume that the output
-// transform will do the right thing with the details
+// Test Cases -- in most of these tests we look for overall structure, assume
+// that the output transform will do the right thing
//----------------------------------------------------------------------------
+ public void testElementToString() throws Exception
+ {
+ Element root = DomUtil.newDocument("foo");
+ Element child1 = DomUtil.appendChild(root, "argle", "bargle");
+
+ assertEquals("{}foo", OutputUtil.elementToString(root));
+ assertEquals("{argle}bargle", OutputUtil.elementToString(child1));
+ }
+
+
+ public void testTreeToString() throws Exception
+ {
+ Element root = DomUtil.newDocument("foo");
+ Element child1 = DomUtil.appendChild(root, "argle", "bargle");
+
+ assertEquals("{}foo\n {argle}bargle", OutputUtil.treeToString(root, 2));
+ assertEquals("{argle}bargle", OutputUtil.treeToString(child1, 2));
+ }
+
+
public void testCompactStringSingleElement() throws Exception
{
Element root = DomUtil.newDocument(EL_ROOT);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-24 00:33:04
|
Revision: 60
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=60&view=rev
Author: kdgregory
Date: 2008-12-24 00:31:26 +0000 (Wed, 24 Dec 2008)
Log Message:
-----------
SchemaUtil.newSchema(): bug 2417477
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java
trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java
Modified: trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java 2008-12-20 12:35:23 UTC (rev 59)
+++ trunk/src/main/java/net/sf/practicalxml/SchemaUtil.java 2008-12-24 00:31:26 UTC (rev 60)
@@ -4,28 +4,69 @@
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
-
-import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
+import org.apache.commons.lang.StringUtils;
+
/**
* A collection of static utility methods for working with XML Schema
* documents. Since <code>javax.xml.validation.Schema</code> is an
* opaque object, most of these actually work with DOM documents that
* contain an XSD.
+ * <p>
+ * <b>Behavior of {@link #newSchema newSchema()} and {@link
+ * #newSchemas newSchemas()}</b>
+ * <p>
+ * These methods exist to create a {@link javax.xml.validation.Schema}
+ * from an XML source. Their basic behavior is to hide the underlying
+ * factory objects, similar to {@link ParseUtil} and {@link OutputUtil}.
+ * However, also they support the creation of <code>Schema<code> objects
+ * from multiple sources, and in this have to deal with a
+ * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6198705">
+ * bug in the JDK</a> (and also in
+ * <a href="http://issues.apache.org/jira/browse/XERCESJ-1130">Xerces</a>)
+ * that prevents the combination of schema documents that specify the same
+ * namespace (this also prevents <xs:import> from working).
+ * <p>
+ * Combining schema documents isn't an easy task, which is probably why the
+ * bug still isn't fixed. The top-level attributes (those attached to the
+ * <code><xs:schema></code> element) are the main problem, as they have
+ * to be consistent across the component schema docs. The approach used by
+ * {@link #newSchema newSchema()} is to take these attributes from the first
+ * source (for {@link #newSchemas newSchemas()}, the first source for a given
+ * namespace URI), and apply the following rules:
+ * <ul>
+ * <li><code>targetNamespace</code>
+ * <br>This must be the same for all source documents processed by {@link
+ * #newSchema newSchema()}; if not, it throws an exception. By comparison,
+ * {@link #newSchemas newSchemas()} will partition source documents by
+ * their value, so an incorrect source document will be silently assigned
+ * its own <code>Schema</code> object.
+ * <li><code>attributeFormDefault</code>, <code>elementFormDefault</code>
+ * <br>The first source document defines these attributes for the resulting
+ * <code>Schema</code> object. If later sources define different values,
+ * those values are ignored. This behavior largely reflects my view of
+ * how an XSD should be modularized (with a single <code>xsd:element
+ * </code> in the first source, type definitions in subsequent sources),
+ * but it is also driven by consistency in instance documents. As a side
+ * note, I strongly recommend that <code>elementFormDefault</code> be
+ * "qualified", as that allows the use of a default namespace in instance
+ * documents.
+ * <li>all other attributes
+ * <br>Are defined by the first source, and ignored on any subsequent sources.
+ * </ul>
*/
public class SchemaUtil
{
private final static String SCHEMA_NS = XMLConstants.W3C_XML_SCHEMA_NS_URI;
- private final static String SCHEMA_PREFIX = "xsd";
- private final static String SCHEMA_ROOT = "schema";
+ private final static String EL_SCHEMA = "schema";
+ private final static String ATTR_TARGET_NS = "targetNamespace";
/**
@@ -42,44 +83,34 @@
/**
- * A workaround for Sun bug <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6198705">
- * 6198705</code>, also known as Xerces bug <a href="http://issues.apache.org/jira/browse/XERCESJ-1130">
- * XERCESJ-1130</code>, which prevents the <code>SchemaFactory.ewSchema</code>
- * method from combining multiple sources that have the same namespace.
- * <p>
- * This method works by parsing the children of the passed sources,
- * verifying that their root element is <code><xsd:schema></code>,
- * combining the children of this root into a new document, and calling
- * <code>newSchema()</code> on the result.
+ * Parses the passed input sources to produce a single <code>Schema</code>
+ * object. All sources must have the same <code>targetNamespace</code>;
+ * other top-level attributes will be taken from the first source.
*
* @param factory Used to create the schema object. This factory's
* <code>ErrorHandler</code> is also used to report
* errors when parsing the source documents.
* @param sources The source schema documents.
*
- * @throws XmlException on any failure that is not handled by the
- * factory's <code>ErrorHandler</code>. This includes parse
- * errors and local validation of the source root element.
+ * @throws IllegalArgumentException if invoked without any sources, or if
+ * a source does not have the target namespace established by the
+ * first source.
+ * @throws XmlException if the sources are not combinable, or on any
+ * failure that is not handled by the factory's <code>ErrorHandler
+ * </code> (including parse errors and local validation of the
+ * source root element).
*/
public static Schema newSchema(SchemaFactory factory, InputSource... sources)
{
- Element combined = DomUtil.newDocument(SCHEMA_NS, SCHEMA_PREFIX + ":" + SCHEMA_ROOT);
- for (InputSource source : sources)
+ if (sources.length == 0)
+ throw new IllegalArgumentException("must specify at least one source");
+
+ Document dom = parse(sources[0]);
+ for (int ii = 1 ; ii < sources.length ; ii++)
{
- combineSchema(combined, source);
+ combine(dom, parse(sources[ii]));
}
-
- try
- {
- synchronized (factory)
- {
- return factory.newSchema(new DOMSource(combined.getOwnerDocument()));
- }
- }
- catch (SAXException e)
- {
- throw new XmlException("unable to generate schema", e);
- }
+ return generate(factory, dom);
}
@@ -88,31 +119,65 @@
//----------------------------------------------------------------------------
/**
- * Parses, verifies, and combines a source document.
+ * Parses an XML document and performs some perfunctory checks to verify
+ * that it's an XML schema. Perhaps in the future we'll add a "validation
+ * level" property that at high levels validates against the "Schema for
+ * Schemas"
*/
- private static void combineSchema(Element newRoot, InputSource source)
+ private static Document parse(InputSource source)
{
- Document doc = ParseUtil.parse(source);
- NamedNodeMap attributeMap = doc.getDocumentElement().getAttributes();
- if (attributeMap != null)
+ Document dom = ParseUtil.parse(source);
+ Element root = dom.getDocumentElement();
+ if (!DomUtil.isNamed(root, SCHEMA_NS, EL_SCHEMA))
{
- for (int i=0; i<attributeMap.getLength(); i++)
- {
- Attr attribute = (Attr) attributeMap.item(i);
- newRoot.setAttribute(attribute.getName(), attribute.getValue());
- }
- }
- Element root = doc.getDocumentElement();
- if (!DomUtil.isNamed(root, SCHEMA_NS, SCHEMA_ROOT))
- {
throw new XmlException("invalid root element name: {"
+ root.getNamespaceURI() + "}"
+ DomUtil.getLocalName(root));
}
- for (Element child : DomUtil.getChildren(root))
+ return dom;
+ }
+
+
+ /**
+ * Merges the second DOM object into the first, verifying that it (1)
+ * claims to be an XML Schema, and (2) has the same root attributes as
+ * the first document.
+ */
+ private static void combine(Document dst, Document src)
+ {
+ Element srcRoot = src.getDocumentElement();
+ Element dstRoot = dst.getDocumentElement();
+
+ String srcTargetNS = srcRoot.getAttribute(ATTR_TARGET_NS);
+ String dstTargetNS = dstRoot.getAttribute(ATTR_TARGET_NS);
+ if (!StringUtils.equals(srcTargetNS, dstTargetNS))
+ throw new IllegalArgumentException(
+ "cannot combine target namespaces: expected "
+ + "\"" + dstTargetNS + "\", was \"" + srcTargetNS + "\"");
+
+ for (Element child : DomUtil.getChildren(srcRoot))
{
- Node tmp = newRoot.getOwnerDocument().importNode(child, true);
- newRoot.appendChild(tmp);
+ Node tmp = dst.importNode(child, true);
+ dstRoot.appendChild(tmp);
}
}
+
+
+ /**
+ * Generates a new <code>Schema</code> object from a DOM document.
+ */
+ private static Schema generate(SchemaFactory factory, Document dom)
+ {
+ try
+ {
+ synchronized (factory)
+ {
+ return factory.newSchema(new DOMSource(dom));
+ }
+ }
+ catch (SAXException e)
+ {
+ throw new XmlException("unable to generate schema", e);
+ }
+ }
}
Modified: trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java 2008-12-20 12:35:23 UTC (rev 59)
+++ trunk/src/test/java/net/sf/practicalxml/TestSchemaUtil.java 2008-12-24 00:31:26 UTC (rev 60)
@@ -1,6 +1,5 @@
package net.sf.practicalxml;
-import java.io.Reader;
import java.io.StringReader;
import javax.xml.validation.Schema;
@@ -16,47 +15,19 @@
extends AbstractTestCase
{
//----------------------------------------------------------------------------
-// Definitions for newSchema() testing
+// Support Code
//----------------------------------------------------------------------------
- public final static String NEW_SCHEMA_START
- = "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">";
- public final static String NEW_SCHEMA_DEF_1
- = "<xsd:element name=\"foo\" type=\"FooType\"/>";
- public final static String NEW_SCHEMA_DEF_2
- = "<xsd:complexType name=\"FooType\">"
- + "<xsd:sequence>"
- + "<xsd:element name=\"argle\" type=\"xsd:integer\"/>"
- + "<xsd:element name=\"bargle\" type=\"BarType\"/>"
- + "</xsd:sequence>"
- + "</xsd:complexType>";
-
- public final static String NEW_SCHEMA_DEF_3
- = "<xsd:simpleType name=\"BarType\">"
- + "<xsd:restriction base=\"xsd:string\">"
- + "</xsd:restriction>"
- + "</xsd:simpleType>";
-
- public final static String NEW_SCHEMA_FINISH
- = "</xsd:schema>";
-
- public final static String NEW_SCHEMA_WITH_NAMESPACE_START
- = "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" targetNamespace=\"http://foo/bar\" xmlns:bar=\"http://foo/bar\" elementFormDefault=\"qualified\">";
-
- public final static String NEW_SCHEMA_WITH_NAMESPACE_DEF_1
- = "<xsd:element name=\"foo\" type=\"bar:FooType\"/>";
-
- public final static String NEW_SCHEMA_WITH_NAMESPACE_DEF_2
- = "<xsd:complexType name=\"FooType\">"
- + "<xsd:sequence>"
- + "<xsd:element name=\"argle\" type=\"xsd:integer\"/>"
- + "</xsd:sequence>"
- + "</xsd:complexType>";
-
//----------------------------------------------------------------------------
// Test Cases
+//
+// Note: since we can't examine a schema once it's compiled, we need to
+// verify newSchema() operation with actual instance docs ... and
+// to make more sense of this, each test case should define its
+// schema and instance docs inline ... yes, that's a lot of repeated
+// XML, but I think it will make verification easier
//----------------------------------------------------------------------------
public void testNewFactory() throws Exception
@@ -69,47 +40,173 @@
}
- public void testNewSchemaWithSingleSource() throws Exception
+ public void testNewSchemaSingleSource() throws Exception
{
- Reader xsd = new StringReader(
- NEW_SCHEMA_START
- + NEW_SCHEMA_DEF_1 + NEW_SCHEMA_DEF_2 + NEW_SCHEMA_DEF_3
- + NEW_SCHEMA_FINISH);
+ String xsd = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'>"
+ + "<xsd:element name='foo' type='FooType'/>"
+ + "<xsd:complexType name='FooType'>"
+ + "<xsd:sequence>"
+ + "<xsd:element name='argle' type='xsd:integer'/>"
+ + "<xsd:element name='bargle' type='BarType'/>"
+ + "</xsd:sequence>"
+ + "</xsd:complexType>"
+ + "<xsd:simpleType name='BarType'>"
+ + "<xsd:restriction base='xsd:string'>"
+ + "</xsd:restriction>"
+ + "</xsd:simpleType>"
+ + "</xsd:schema>";
+ String xml = "<foo>"
+ + "<argle>12</argle>"
+ + "<bargle>test</bargle>"
+ + "</foo>";
+
Schema schema = SchemaUtil.newSchema(
SchemaUtil.newFactory(new ExceptionErrorHandler()),
- new InputSource(xsd));
+ new InputSource(new StringReader(xsd)));
+
assertNotNull(schema);
+ ParseUtil.validatingParse(new InputSource(new StringReader(xml)),
+ schema,
+ new ExceptionErrorHandler());
}
- public void testNewSchemaWithMultipleSources() throws Exception
+ public void testNewSchemaMultipleSources() throws Exception
{
- Reader xsd1 = new StringReader(
- NEW_SCHEMA_START + NEW_SCHEMA_DEF_1 + NEW_SCHEMA_FINISH);
- Reader xsd2 = new StringReader(
- NEW_SCHEMA_START + NEW_SCHEMA_DEF_2 + NEW_SCHEMA_FINISH);
- Reader xsd3 = new StringReader(
- NEW_SCHEMA_START + NEW_SCHEMA_DEF_3 + NEW_SCHEMA_FINISH);
+ String xsd1 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'>"
+ + "<xsd:element name='foo' type='FooType'/>"
+ + "</xsd:schema>";
+ String xsd2 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'>"
+ + "<xsd:complexType name='FooType'>"
+ + "<xsd:sequence>"
+ + "<xsd:element name='argle' type='xsd:integer'/>"
+ + "<xsd:element name='bargle' type='BarType'/>"
+ + "</xsd:sequence>"
+ + "</xsd:complexType>"
+ + "</xsd:schema>";
+ String xsd3 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'>"
+ + "<xsd:simpleType name='BarType'>"
+ + "<xsd:restriction base='xsd:string'>"
+ + "</xsd:restriction>"
+ + "</xsd:simpleType>"
+ + "</xsd:schema>";
+ String xml = "<foo>"
+ + "<argle>12</argle>"
+ + "<bargle>test</bargle>"
+ + "</foo>";
+
Schema schema = SchemaUtil.newSchema(
SchemaUtil.newFactory(new ExceptionErrorHandler()),
- new InputSource(xsd1),
- new InputSource(xsd2),
- new InputSource(xsd3));
+ new InputSource(new StringReader(xsd1)),
+ new InputSource(new StringReader(xsd2)),
+ new InputSource(new StringReader(xsd3)));
+
assertNotNull(schema);
+ ParseUtil.validatingParse(new InputSource(new StringReader(xml)),
+ schema,
+ new ExceptionErrorHandler());
}
-
- public void testNewSchemaWithNamespace() throws Exception
+
+
+ public void testNewSchemaSingleSourceWithNamespace() throws Exception
{
- Reader xsd = new StringReader(
- NEW_SCHEMA_WITH_NAMESPACE_START
- + NEW_SCHEMA_WITH_NAMESPACE_DEF_1 + NEW_SCHEMA_WITH_NAMESPACE_DEF_2
- + NEW_SCHEMA_FINISH);
+ String xsd = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " xmlns='http://foo.example.com'"
+ + " targetNamespace='http://foo.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:element name='foo' type='FooType'/>"
+ + "<xsd:complexType name='FooType'>"
+ + "<xsd:sequence>"
+ + "<xsd:element name='argle' type='xsd:integer'/>"
+ + "</xsd:sequence>"
+ + "</xsd:complexType>"
+ + "</xsd:schema>";
+ String xml = "<foo xmlns='http://foo.example.com'>"
+ + "<argle>12</argle>"
+ + "</foo>";
+
Schema schema = SchemaUtil.newSchema(
SchemaUtil.newFactory(new ExceptionErrorHandler()),
- new InputSource(xsd));
+ new InputSource(new StringReader(xsd)));
+
assertNotNull(schema);
+ ParseUtil.validatingParse(new InputSource(new StringReader(xml)),
+ schema,
+ new ExceptionErrorHandler());
}
+
+
+ public void testNewSchemaMultipleSourceWithNamespace() throws Exception
+ {
+ String xsd1 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " xmlns='http://foo.example.com'"
+ + " targetNamespace='http://foo.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:element name='foo' type='FooType'/>"
+ + "</xsd:schema>";
+ String xsd2 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://foo.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:complexType name='FooType'>"
+ + "<xsd:sequence>"
+ + "<xsd:element name='argle' type='xsd:integer'/>"
+ + "</xsd:sequence>"
+ + "</xsd:complexType>"
+ + "</xsd:schema>";
+
+ String xml = "<foo xmlns='http://foo.example.com'>"
+ + "<argle>12</argle>"
+ + "</foo>";
+
+ Schema schema = SchemaUtil.newSchema(
+ SchemaUtil.newFactory(new ExceptionErrorHandler()),
+ new InputSource(new StringReader(xsd1)),
+ new InputSource(new StringReader(xsd2)));
+
+ assertNotNull(schema);
+ ParseUtil.validatingParse(new InputSource(new StringReader(xml)),
+ schema,
+ new ExceptionErrorHandler());
+ }
+
+
+ public void testNewSchemaFailMultipleNamepaces() throws Exception
+ {
+ String xsd1 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " xmlns:foo='http://foo.example.com'"
+ + " targetNamespace='http://foo.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:element name='foo' type='foo:FooType'/>"
+ + "</xsd:schema>";
+ String xsd2 = "<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'"
+ + " targetNamespace='http://bar.example.com'"
+ + " elementFormDefault='qualified'"
+ + ">"
+ + "<xsd:complexType name='FooType'>"
+ + "<xsd:sequence>"
+ + "<xsd:element name='argle' type='xsd:integer'/>"
+ + "</xsd:sequence>"
+ + "</xsd:complexType>"
+ + "</xsd:schema>";
+
+ try
+ {
+ SchemaUtil.newSchema(
+ SchemaUtil.newFactory(new ExceptionErrorHandler()),
+ new InputSource(new StringReader(xsd1)),
+ new InputSource(new StringReader(xsd2)));
+ fail("combined schemas with different target namespaces");
+ }
+ catch (IllegalArgumentException ee)
+ {
+ // success
+ }
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-20 12:35:26
|
Revision: 59
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=59&view=rev
Author: kdgregory
Date: 2008-12-20 12:35:23 +0000 (Sat, 20 Dec 2008)
Log Message:
-----------
Add in-situ tests for Uppercase and Lowercase
Modified Paths:
--------------
trunk/src/test/java/net/sf/practicalxml/xpath/function/TestLowercase.java
trunk/src/test/java/net/sf/practicalxml/xpath/function/TestUppercase.java
Modified: trunk/src/test/java/net/sf/practicalxml/xpath/function/TestLowercase.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/xpath/function/TestLowercase.java 2008-12-20 11:29:17 UTC (rev 58)
+++ trunk/src/test/java/net/sf/practicalxml/xpath/function/TestLowercase.java 2008-12-20 12:35:23 UTC (rev 59)
@@ -2,18 +2,53 @@
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import javax.xml.xpath.XPathFunctionException;
-
import org.w3c.dom.Element;
+import org.w3c.dom.Node;
import net.sf.practicalxml.AbstractTestCase;
import net.sf.practicalxml.DomUtil;
+import net.sf.practicalxml.XPathWrapper;
public class TestLowercase
extends AbstractTestCase
{
+ public TestLowercase(String name)
+ {
+ super(name);
+ }
+
+
+//----------------------------------------------------------------------------
+// Setup
+//----------------------------------------------------------------------------
+
+ private Element _root;
+ private Element _child1;
+ private Element _child2;
+ private Element _child3;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ _root = DomUtil.newDocument("foo");
+ _child1 = DomUtil.appendChild(_root, "bar");
+ _child2 = DomUtil.appendChild(_root, "baz");
+ _child3 = DomUtil.appendChild(_root, "foo2");
+
+ DomUtil.setText(_root, "Test");
+ DomUtil.setText(_child1, "Test1");
+ DomUtil.setText(_child2, "Test2");
+ }
+
+
+//----------------------------------------------------------------------------
+// Test Cases
+//----------------------------------------------------------------------------
+
public void testConstruction() throws Exception
{
Lowercase fn = new Lowercase();
@@ -23,6 +58,7 @@
assertEquals(1, fn.getMaxArgCount());
}
+
public void testLiteralString() throws Exception
{
assertEquals(
@@ -33,26 +69,17 @@
public void testNodeList() throws Exception
{
- Element root = DomUtil.newDocument("foo");
- Element child1 = DomUtil.appendChild(root, "bar");
- Element child2 = DomUtil.appendChild(root, "baz");
- DomUtil.setText(root, "Test");
- DomUtil.setText(child1, "Test2");
- DomUtil.setText(child2, "Test3");
-
assertEquals(
- "test2",
- new Lowercase().evaluate(Arrays.asList(root.getChildNodes())));
+ "test1",
+ new Lowercase().evaluate(Arrays.asList(_root.getChildNodes())));
}
public void testEmptyNodeList() throws Exception
{
- Element root = DomUtil.newDocument("foo");
-
assertEquals(
"",
- new Lowercase().evaluate(Arrays.asList(root.getChildNodes())));
+ new Lowercase().evaluate(Arrays.asList(_child3.getChildNodes())));
}
@@ -77,4 +104,16 @@
}
}
+
+ public void testInSitu() throws Exception
+ {
+ XPathWrapper xpath1 = new XPathWrapper("//*[ns:lowercase(text()) = 'test1']")
+ .bindFunction(new Lowercase(), "ns");
+ List<Node> result1 = xpath1.evaluate(_root);
+ assertSame(_child1, result1.get(0));
+
+ XPathWrapper xpath2 = new XPathWrapper("//*[ns:lowercase(text()) = 'TEST1']")
+ .bindFunction(new Lowercase(), "ns");
+ assertEquals(0, xpath2.evaluate(_root).size());
+ }
}
Modified: trunk/src/test/java/net/sf/practicalxml/xpath/function/TestUppercase.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/xpath/function/TestUppercase.java 2008-12-20 11:29:17 UTC (rev 58)
+++ trunk/src/test/java/net/sf/practicalxml/xpath/function/TestUppercase.java 2008-12-20 12:35:23 UTC (rev 59)
@@ -2,18 +2,53 @@
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import javax.xml.xpath.XPathFunctionException;
-
import org.w3c.dom.Element;
+import org.w3c.dom.Node;
import net.sf.practicalxml.AbstractTestCase;
import net.sf.practicalxml.DomUtil;
+import net.sf.practicalxml.XPathWrapper;
public class TestUppercase
extends AbstractTestCase
{
+ public TestUppercase(String name)
+ {
+ super(name);
+ }
+
+
+//----------------------------------------------------------------------------
+// Setup
+//----------------------------------------------------------------------------
+
+ private Element _root;
+ private Element _child1;
+ private Element _child2;
+ private Element _child3;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ _root = DomUtil.newDocument("foo");
+ _child1 = DomUtil.appendChild(_root, "bar");
+ _child2 = DomUtil.appendChild(_root, "baz");
+ _child3 = DomUtil.appendChild(_root, "foo2");
+
+ DomUtil.setText(_root, "Test");
+ DomUtil.setText(_child1, "Test1");
+ DomUtil.setText(_child2, "Test2");
+ }
+
+
+//----------------------------------------------------------------------------
+// Test Cases
+//----------------------------------------------------------------------------
+
public void testConstruction() throws Exception
{
Uppercase fn = new Uppercase();
@@ -23,6 +58,7 @@
assertEquals(1, fn.getMaxArgCount());
}
+
public void testLiteralString() throws Exception
{
assertEquals(
@@ -33,26 +69,17 @@
public void testNodeList() throws Exception
{
- Element root = DomUtil.newDocument("foo");
- Element child1 = DomUtil.appendChild(root, "bar");
- Element child2 = DomUtil.appendChild(root, "baz");
- DomUtil.setText(root, "Test");
- DomUtil.setText(child1, "Test2");
- DomUtil.setText(child2, "Test3");
-
assertEquals(
- "TEST2",
- new Uppercase().evaluate(Arrays.asList(root.getChildNodes())));
+ "TEST1",
+ new Uppercase().evaluate(Arrays.asList(_root.getChildNodes())));
}
public void testEmptyNodeList() throws Exception
{
- Element root = DomUtil.newDocument("foo");
-
assertEquals(
"",
- new Lowercase().evaluate(Arrays.asList(root.getChildNodes())));
+ new Uppercase().evaluate(Arrays.asList(_child3.getChildNodes())));
}
@@ -77,4 +104,17 @@
}
}
+
+ public void testInSitu() throws Exception
+ {
+ XPathWrapper xpath1 = new XPathWrapper("//*[ns:uppercase(text()) = 'TEST1']")
+ .bindFunction(new Uppercase(), "ns");
+ List<Node> result1 = xpath1.evaluate(_root);
+ assertSame(_child1, result1.get(0));
+
+ XPathWrapper xpath2 = new XPathWrapper("//*[ns:uppercase(text()) = 'test1']")
+ .bindFunction(new Uppercase(), "ns");
+ assertEquals(0, xpath2.evaluate(_root).size());
+ }
+
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: Auto-Generated S. C. M. <pra...@li...> - 2008-12-20 11:29:20
|
Revision: 58
http://practicalxml.svn.sourceforge.net/practicalxml/?rev=58&view=rev
Author: kdgregory
Date: 2008-12-20 11:29:17 +0000 (Sat, 20 Dec 2008)
Log Message:
-----------
add FunctionResolver
update XPathWrapper to use it
Modified Paths:
--------------
trunk/src/main/java/net/sf/practicalxml/XPathWrapper.java
trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java
trunk/src/test/java/net/sf/practicalxml/TestXPathWrapper.java
trunk/src/test/java/net/sf/practicalxml/xpath/TestAbstractFunction.java
Added Paths:
-----------
trunk/src/main/java/net/sf/practicalxml/xpath/FunctionResolver.java
trunk/src/test/java/net/sf/practicalxml/xpath/TestFunctionResolver.java
Modified: trunk/src/main/java/net/sf/practicalxml/XPathWrapper.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/XPathWrapper.java 2008-12-17 14:03:16 UTC (rev 57)
+++ trunk/src/main/java/net/sf/practicalxml/XPathWrapper.java 2008-12-20 11:29:17 UTC (rev 58)
@@ -11,7 +11,6 @@
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathFunction;
-import javax.xml.xpath.XPathFunctionResolver;
import javax.xml.xpath.XPathVariableResolver;
import org.w3c.dom.Document;
@@ -19,6 +18,8 @@
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import net.sf.practicalxml.xpath.AbstractFunction;
+import net.sf.practicalxml.xpath.FunctionResolver;
import net.sf.practicalxml.xpath.NamespaceResolver;
@@ -34,7 +35,7 @@
private final String _expr;
private final NamespaceResolver _nsResolver = new NamespaceResolver();
private Map<QName,Object> _variables = new HashMap<QName,Object>();
- private Map<QName,XPathFunction> _functions = new HashMap<QName,XPathFunction>();
+ private FunctionResolver _functions = new FunctionResolver();
private XPathExpression _compiled;
@@ -129,22 +130,127 @@
/**
- * Binds a function to this expression, replacing any previous binding
- * for the specified name. Note that <code>XPathFunctionResolver</code>
- * can support multiple functions with the same name; we don't.
+ * Binds an {@link net.sf.practicalxml.xpath.AbstractFunction} to this
+ * expression. Subsequent calls to this method with the same name will
+ * silently replace the binding.
* <p>
* Per the JDK documentation, user-defined functions must occupy their
- * own namespace. You will need to add a namespace binding along with
- * your function binding.
+ * own namespace. You must bind a namespace for this function, and use
+ * the bound prefix to reference it in your expression. Alternatively,
+ * you can call the variant of <code>bindFunction()</code> that binds
+ * a prefix to the function's namespace.
*
- * @param name The fully-qualified name for this binding.
+ * @param func The function.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindFunction(AbstractFunction func)
+ {
+ _functions.addFunction(func);
+ return this;
+ }
+
+
+ /**
+ * Binds an {@link net.sf.practicalxml.xpath.AbstractFunction} to this
+ * expression, along with the prefix used to access that function.
+ * Subsequent calls to this method with the same name will silently
+ * replace the binding.
+ * <p>
+ * Per the JDK documentation, user-defined functions must occupy their
+ * own namespace. This method will retrieve the namespace from the
+ * function, and bind it to the passed prefix.
+ *
+ * @param func The function.
+ * @param prefix The prefix to bind to this function's namespace.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindFunction(AbstractFunction func, String prefix)
+ {
+ _functions.addFunction(func);
+ return bindNamespace(prefix, func.getNamespaceUri());
+ }
+
+
+ /**
+ * Binds a standard <code>XPathFunction</code> to this expression,
+ * handling any number of arguments. Subsequent calls to this method
+ * with the same name will silently replace the binding.
+ * <p>
+ * Per the JDK documentation, user-defined functions must occupy their
+ * own namespace. If the qualified name that you pass to this method
+ * includes a prefix, the associated namespace will be bound to that
+ * prefix. If not, you must bind the namespace explicitly. In either
+ * case, you must refer to the function in your expression using a
+ * bound prefix.
+ *
+ * @param name The qualified name for this function. Must contain
+ * a name and namespace, may contain a prefix.
* @param func The function to bind to this name.
*
* @return The wrapper, so that calls may be chained.
*/
public XPathWrapper bindFunction(QName name, XPathFunction func)
{
- _functions.put(name, func);
+ return bindFunction(name, func, 0, Integer.MAX_VALUE);
+ }
+
+
+ /**
+ * Binds a standard <code>XPathFunction</code> to this expression,
+ * handling a specific number of arguments. Subsequent calls to this
+ * method with the same name and arity will silently replace the binding.
+ * <p>
+ * Per the JDK documentation, user-defined functions must occupy their
+ * own namespace. If the qualified name that you pass to this method
+ * includes a prefix, the associated namespace will be bound to that
+ * prefix. If not, you must bind the namespace explicitly. In either
+ * case, you must refer to the function in your expression using a
+ * bound prefix.
+ *
+ * @param name The qualified name for this function. Must contain
+ * a name and namespace, may contain a prefix.
+ * @param func The function to bind to this name.
+ * @param arity The number of arguments accepted by this function.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindFunction(QName name, XPathFunction func, int arity)
+ {
+ return bindFunction(name, func, arity, arity);
+ }
+
+
+ /**
+ * Binds a standard <code>XPathFunction</code> to this expression,
+ * handling a specific range of arguments. Subsequent calls to this
+ * method with the same name and range of arguments will silently
+ * replace the binding.
+ * <p>
+ * Per the JDK documentation, user-defined functions must occupy their
+ * own namespace. If the qualified name that you pass to this method
+ * includes a prefix, the associated namespace will be bound to that
+ * prefix. If not, you must bind the namespace explicitly. In either
+ * case, you must refer to the function in your expression using a
+ * bound prefix.
+ *
+ * @param name The qualified name for this function. Must contain
+ * a name and namespace, may contain a prefix.
+ * @param func The function to bind to this name.
+ * @param minArity The minimum number of arguments accepted by this
+ * function.
+ * @param maxArity The maximum number of arguments accepted by this
+ * function.
+ *
+ * @return The wrapper, so that calls may be chained.
+ */
+ public XPathWrapper bindFunction(QName name, XPathFunction func,
+ int minArity, int maxArity)
+ {
+ _functions.addFunction(func, name, minArity, maxArity);
+ if (!"".equals(name.getPrefix()))
+ bindNamespace(name.getPrefix(), name.getNamespaceURI());
return this;
}
@@ -335,7 +441,7 @@
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(_nsResolver);
xpath.setXPathVariableResolver(new MyVariableResolver());
- xpath.setXPathFunctionResolver(new MyFunctionResolver());
+ xpath.setXPathFunctionResolver(_functions);
_compiled = xpath.compile(_expr);
}
catch (XPathExpressionException ee)
@@ -356,18 +462,4 @@
return _variables.get(name);
}
}
-
-
- /**
- * Resolver for function references. Note that we ignore the "arity"
- * argument, meaning that there's a single binding per name.
- */
- private class MyFunctionResolver
- implements XPathFunctionResolver
- {
- public XPathFunction resolveFunction(QName name, int arity)
- {
- return _functions.get(name);
- }
- }
}
Modified: trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java 2008-12-17 14:03:16 UTC (rev 57)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/AbstractFunction.java 2008-12-20 11:29:17 UTC (rev 58)
@@ -67,9 +67,7 @@
*/
protected AbstractFunction(String nsUri, String localName)
{
- _qname = new QName(nsUri, localName);
- _minArgCount = 0;
- _maxArgCount = Integer.MAX_VALUE;
+ this(nsUri, localName, 0, Integer.MAX_VALUE);
}
@@ -78,9 +76,7 @@
*/
protected AbstractFunction(String nsUri, String localName, int numArgs)
{
- _qname = new QName(nsUri, localName);
- _minArgCount = numArgs;
- _maxArgCount = numArgs;
+ this(nsUri, localName, numArgs, numArgs);
}
@@ -89,7 +85,16 @@
*/
protected AbstractFunction(String nsUri, String localName, int minArgs, int maxArgs)
{
- _qname = new QName(nsUri, localName);
+ this(new QName(nsUri, localName), minArgs, maxArgs);
+ }
+
+
+ /**
+ * Base constructor.
+ */
+ protected AbstractFunction(QName qname, int minArgs, int maxArgs)
+ {
+ _qname = qname;
_minArgCount = minArgs;
_maxArgCount = maxArgs;
}
@@ -152,12 +157,25 @@
public boolean isMatch(QName qname, int arity)
{
return _qname.equals(qname)
- && (arity >= _minArgCount)
- && (arity <= _maxArgCount);
+ && (arity >= _minArgCount)
+ && (arity <= _maxArgCount);
}
+
+ /**
+ * Determines whether this function can handle the specified number of
+ * arguments. This is used by {@link FunctionResolver}, which already
+ * knows that the QName matches.
+ */
+ public boolean isArityMatch(int arity)
+ {
+ return (arity >= _minArgCount)
+ && (arity <= _maxArgCount);
+ }
+
+
//----------------------------------------------------------------------------
-// Implementation of Comparable
+// Implementation of Comparable, Object overrides
//----------------------------------------------------------------------------
/**
@@ -197,6 +215,40 @@
}
+ /**
+ * Two instances are considered equal if they have the same qualified
+ * name and accept the same range of arguments. This supports use with
+ * the collections framework, which is the only place that you should
+ * be checking equality.
+ */
+ @Override
+ public final boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ else if (obj instanceof AbstractFunction<?>)
+ {
+ AbstractFunction<?> that = (AbstractFunction<?>)obj;
+ return this._qname.equals(that._qname)
+ && this._minArgCount == that._minArgCount
+ && this._maxArgCount == that._maxArgCount;
+ }
+ else
+ return false;
+ }
+
+
+ /**
+ * Hashcode is based on the qualified name, does not consider argument
+ * count.
+ */
+ @Override
+ public final int hashCode()
+ {
+ return _qname.hashCode();
+ }
+
+
//----------------------------------------------------------------------------
// Implementation of XPathFunction
//----------------------------------------------------------------------------
@@ -376,6 +428,22 @@
* Processes a <code>null</code> argument — it's unclear whether
* this can ever happen. The default implementation throws <code>
* IllegalArgumentException</code>.
+
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ // FIXME - implement
+ return super.equals(obj);
+ }
+
+
+ @Override
+ public int hashCode()
+ {
+ // FIXME - implement
+ return super.hashCode();
+ }
*
* @param index Index of the argument, numbered from 0.
* @param helper Helper object to preserve intermediate results.
Added: trunk/src/main/java/net/sf/practicalxml/xpath/FunctionResolver.java
===================================================================
--- trunk/src/main/java/net/sf/practicalxml/xpath/FunctionResolver.java (rev 0)
+++ trunk/src/main/java/net/sf/practicalxml/xpath/FunctionResolver.java 2008-12-20 11:29:17 UTC (rev 58)
@@ -0,0 +1,266 @@
+package net.sf.practicalxml.xpath;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeSet;
+
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+import javax.xml.xpath.XPathFunctionResolver;
+
+
+/**
+ * An <code>XPathFunctionResolver</code> designed for use with subclasses of
+ * {@link AbstractFunction} (but will work with any <code>XPathFunction</code>).
+ * Functions are resolved based on name, namespace, and arity. Where multiple
+ * eligible functions have the same name and namespace, the comparison rules of
+ * <code>AbstractFunction</code> are used to pick the most appropriate function:
+ * smaller range of accepted arguments first, followed by lower minimum argument
+ * count.
+ * <p>
+ * This object follows the builder pattern: <code>addFunction()</code> returns
+ * the object itself, so that calls may be chained.
+ */
+public class FunctionResolver
+implements XPathFunctionResolver
+{
+ private Map<QName,FunctionHolder> _table = new HashMap<QName,FunctionHolder>();
+
+//----------------------------------------------------------------------------
+// Public Methods
+//----------------------------------------------------------------------------
+
+ /**
+ * Adds a subclass of {@link AbstractFunction} to this resolver. This
+ * function provides its own information about name, namespace, and
+ * supported number of arguments.
+ * <p>
+ * If the same function has already been added, will silently replace it.
+ *
+ * @return The resolver, so that calls may be chained.
+ */
+ public FunctionResolver addFunction(AbstractFunction<?> func)
+ {
+ FunctionHolder holder = _table.get(func.getQName());
+ if (holder == null)
+ {
+ holder = new FunctionHolder(func);
+ _table.put(func.getQName(), holder);
+ }
+ else
+ {
+ holder.put(func);
+ }
+ return this;
+ }
+
+
+ /**
+ * Adds a normal <code>XPathFunction</code> to this resolver, without
+ * specifying argument count. This function will be chosen for any number
+ * of arguments, provided that there is not a more-specific binding).
+ * <p>
+ * If a function has already been added with the same name and argument
+ * range, this call will silently replace it.
+ * <p>
+ * Note: the resolver wraps the passed function with a decorator that
+ * allows it to be managed. The resolver will return this decorator
+ * object rather than the original function.
+ *
+ * @return The resolver, so that calls may be chained.
+ */
+ public FunctionResolver addFunction(XPathFunction func, QName name)
+ {
+ return addFunction(func, name, 0, Integer.MAX_VALUE);
+ }
+
+
+ /**
+ * Adds a normal <code>XPathFunction</code> to this resolver. Specifies
+ * the exact number of arguments for which this function will be chosen.
+ * <p>
+ * If a function has already been added with the same name and argument
+ * range, this call will silently replace it.
+ * <p>
+ * Note: the resolver wraps the passed function with a decorator that
+ * allows it to be managed. The resolver will return this decorator
+ * object rather than the original function.
+ *
+ * @return The resolver, so that calls may be chained.
+ */
+ public FunctionResolver addFunction(XPathFunction func, QName name, int argCount)
+ {
+ return addFunction(func, name, argCount, argCount);
+ }
+
+
+ /**
+ * Adds a normal <code>XPathFunction</code> to this resolver. Specifies
+ * the minimum and maximum number of arguments for which this function
+ * will be chosen.
+ * <p>
+ * If a function has already been added with the same name and argument
+ * range, this call will silently replace it.
+ * <p>
+ * Note: the resolver wraps the passed function with a decorator that
+ * allows it to be managed. The resolver will return this decorator
+ * object rather than the original function.
+ *
+ * @return The resolver, so that calls may be chained.
+ */
+ public FunctionResolver addFunction(XPathFunction func, QName name, int minArgCount, int maxArgCount)
+ {
+ return addFunction(new StandardFunctionAdapter(func, name, minArgCount, maxArgCount));
+ }
+
+
+//----------------------------------------------------------------------------
+// XPathFunctionResolver
+//----------------------------------------------------------------------------
+
+ /**
+ * Picks the "most eligble" function of those bound to this resolver.
+ * If unable to find any function that matches, returns <code>null</code>.
+ */
+ public XPathFunction resolveFunction(QName functionName, int arity)
+ {
+ FunctionHolder holder = _table.get(functionName);
+ return (holder != null) ? holder.get(arity)
+ : null;
+ }
+
+
+//----------------------------------------------------------------------------
+// Object overrides
+//----------------------------------------------------------------------------
+
+ /**
+ * Two instances are equal if they have the same number of functions,
+ * and each has a counterpart with the same QName and arity range (but
+ * not the same implementation).
+ */
+ @Override
+ public final boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ else if (obj instanceof FunctionResolver)
+ return this._table.equals(((FunctionResolver)obj)._table);
+ else
+ return false;
+ }
+
+
+ @Override
+ public final int hashCode()
+ {
+ // I suspect this is a very inefficient way to compute hashcode,
+ // but this object should never be stored in a hashing structure
+ // -- if you need to do that, come up with a better implementation
+ return _table.keySet().hashCode();
+ }
+
+
+//----------------------------------------------------------------------------
+// Internals
+//----------------------------------------------------------------------------
+
+ /**
+ * Holder for AbstractFunction instances. Can deal with 1 or N, and
+ * pick the appropriate one for a particular evaluation.
+ */
+ private static class FunctionHolder
+ {
+ private AbstractFunction<?> _onlyOne;
+ private TreeSet<AbstractFunction<?>> _hasMany;
+
+ public FunctionHolder(AbstractFunction<?> initial)
+ {
+ _onlyOne = initial;
+ }
+
+ public void put(AbstractFunction<?> func)
+ {
+ if (_hasMany != null)
+ {
+ // remove old implementation if it exists
+ _hasMany.remove(func);
+ _hasMany.add(func);
+ }
+ else if (_onlyOne.equals(func))
+ {
+ _onlyOne = func;
+ }
+ else
+ {
+ _hasMany = new TreeSet<AbstractFunction<?>>();
+ _hasMany.add(func);
+ _hasMany.add(_onlyOne);
+ _onlyOne = null;
+ }
+ }
+
+ public AbstractFunction<?> get(int arity)
+ {
+ if (_onlyOne != null)
+ {
+ return (_onlyOne.isArityMatch(arity))
+ ? _onlyOne
+ : null;
+ }
+
+ for (AbstractFunction<?> func : _hasMany)
+ {
+ if (func.isArityMatch(arity))
+ return func;
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ // if this ever fails, someone needs to fix their code
+ FunctionHolder that = (FunctionHolder)obj;
+
+ return (_onlyOne != null)
+ ? this._onlyOne.equals(that._onlyOne)
+ : this._hasMany.equals(that._hasMany);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ // I know this will never be stored as the key of a hash-table,
+ // but I want to keep static analysis tools quiet
+ return 0;
+ }
+ }
+
+
+ /**
+ * Adapter for standard XPathFunction instances, allowing them to be
+ * managed by this resolver.
+ */
+ private static class StandardFunctionAdapter
+ extends AbstractFunction<Object>
+ {
+ final XPathFunction _func;
+
+ public StandardFunctionAdapter(XPathFunction func, QName name, int minArgCount, int maxArgCount)
+ {
+ super(name, minArgCount, maxArgCount);
+ _func = func;
+ }
+
+ @Override
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ return _func.evaluate(args);
+ }
+ }
+}
Modified: trunk/src/test/java/net/sf/practicalxml/TestXPathWrapper.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/TestXPathWrapper.java 2008-12-17 14:03:16 UTC (rev 57)
+++ trunk/src/test/java/net/sf/practicalxml/TestXPathWrapper.java 2008-12-20 11:29:17 UTC (rev 58)
@@ -5,6 +5,8 @@
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
+import net.sf.practicalxml.xpath.AbstractFunction;
+
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -50,7 +52,42 @@
// Support Code
//----------------------------------------------------------------------------
+ /**
+ * A standard XPath function implementation that returns the namespace
+ * of the first selected node.
+ */
+ private static class MyStandardFunction
+ implements XPathFunction
+ {
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ NodeList arg = (NodeList)args.get(0);
+ return arg.item(0).getNamespaceURI();
+ }
+ }
+
+ /**
+ * An <code>AbstractFunction</code> implementation that returns the
+ * namespace of the first selected node.
+ */
+ private static class MyAbstractFunction
+ extends AbstractFunction<String>
+ {
+ public MyAbstractFunction(String nsUri, String name)
+ {
+ super(nsUri, name);
+ }
+
+ @Override
+ protected String processArg(int index, Node value, String helper)
+ throws Exception
+ {
+ return value.getNamespaceURI();
+ }
+ }
+
//----------------------------------------------------------------------------
// Test Cases
//----------------------------------------------------------------------------
@@ -158,31 +195,62 @@
}
- public void testFunctions() throws Exception
+ public void testAbstractFunctions() throws Exception
{
- _child1.setAttribute("bar", "baz");
- _child2.setAttribute("bar", "bargle");
+ XPathWrapper xpath1 = new XPathWrapper("ns:myfunc(.)")
+ .bindNamespace("ns", NS1)
+ .bindFunction(new MyAbstractFunction(NS1, "myfunc"));
- XPathFunction myfunc = new XPathFunction() {
- public Object evaluate(List args)
- throws XPathFunctionException
- {
- NodeList arg = (NodeList)args.get(0);
- Element asElem = (Element)arg.item(0);
- return asElem.getAttribute("bar");
- }
- };
+ assertEquals("", xpath1.evaluateAsString(_child1));
+ assertEquals(NS1, xpath1.evaluateAsString(_child2));
- XPathWrapper xpath = new XPathWrapper("ns:myfunc(.)")
- .bindNamespace("ns", NS1)
- .bindFunction(new QName(NS1, "myfunc"), myfunc);
+ XPathWrapper xpath2 = new XPathWrapper("ns:myfunc(.)")
+ .bindFunction(new MyAbstractFunction(NS1, "myfunc"), "ns");
- assertEquals("baz", xpath.evaluateAsString(_child1));
- assertEquals("bargle", xpath.evaluateAsString(_child2));
+ assertEquals("", xpath2.evaluateAsString(_child1));
+ assertEquals(NS1, xpath2.evaluateAsString(_child2));
}
+ public void testStandardFunctions() throws Exception
+ {
+ XPathWrapper xpath1 = new XPathWrapper("ns:myfunc(.)")
+ .bindFunction(new QName(NS1, "myfunc", "ns"),
+ new MyStandardFunction());
+ assertEquals("", xpath1.evaluateAsString(_child1));
+ assertEquals(NS1, xpath1.evaluateAsString(_child2));
+
+ XPathWrapper xpath2 = new XPathWrapper("ns:myfunc(.,.)")
+ .bindFunction(new QName(NS2, "myfunc", "ns"),
+ new MyStandardFunction(),
+ 2);
+
+ assertEquals("", xpath2.evaluateAsString(_child1));
+ assertEquals(NS1, xpath2.evaluateAsString(_child2));
+ }
+
+
+ public void testUnresolvableFunction() throws Exception
+ {
+ // we call with two arguments, it only gets resolved for one
+ XPathWrapper xpath1 = new XPathWrapper("ns:myfunc(.,.)")
+ .bindFunction(new QName(NS2, "myfunc", "ns"),
+ new MyStandardFunction(),
+ 1);
+ try
+ {
+ xpath1.evaluateAsString(_child1);
+ fail("didn't throw even though arity was wrong");
+ }
+ catch (XmlException ee)
+ {
+ // success
+ }
+ }
+
+
+
public void testEqualsAndHashCode() throws Exception
{
Object obj1a = new XPathWrapper("//foo");
Modified: trunk/src/test/java/net/sf/practicalxml/xpath/TestAbstractFunction.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/xpath/TestAbstractFunction.java 2008-12-17 14:03:16 UTC (rev 57)
+++ trunk/src/test/java/net/sf/practicalxml/xpath/TestAbstractFunction.java 2008-12-20 11:29:17 UTC (rev 58)
@@ -359,4 +359,31 @@
assertEquals(1, fn3.compareTo(fn4));
assertEquals(-1, fn4.compareTo(fn3));
}
+
+ public void testEqualsAndHashcode() throws Exception
+ {
+ AbstractFunction<Object> fn1 = new AbstractFunction<Object>("foo", "bar", 1, 4);
+ AbstractFunction<Object> fn2 = new AbstractFunction<Object>("foo", "bar", 3);
+ AbstractFunction<Object> fn3 = new AbstractFunction<Object>("foo", "bar", 3);
+ AbstractFunction<Object> fn4 = new AbstractFunction<Object>("foo", "baz", 3);
+ AbstractFunction<Object> fn5 = new AbstractFunction<Object>("fzz", "bar", 3);
+
+ assertFalse(fn1.equals(fn2));
+ assertFalse(fn2.equals(fn1));
+
+ assertTrue(fn2.equals(fn3));
+ assertTrue(fn3.equals(fn2));
+
+ assertFalse(fn2.equals(fn4));
+ assertFalse(fn4.equals(fn2));
+
+ assertFalse(fn2.equals(fn5));
+ assertFalse(fn5.equals(fn2));
+
+ assertEquals(fn1.hashCode(), fn2.hashCode());
+ assertEquals(fn2.hashCode(), fn3.hashCode());
+
+ // as of JDK 1.5, this is known to be true; it shouldn't change
+ assertTrue(fn1.hashCode() != fn4.hashCode());
+ }
}
Added: trunk/src/test/java/net/sf/practicalxml/xpath/TestFunctionResolver.java
===================================================================
--- trunk/src/test/java/net/sf/practicalxml/xpath/TestFunctionResolver.java (rev 0)
+++ trunk/src/test/java/net/sf/practicalxml/xpath/TestFunctionResolver.java 2008-12-20 11:29:17 UTC (rev 58)
@@ -0,0 +1,227 @@
+package net.sf.practicalxml.xpath;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+
+import net.sf.practicalxml.AbstractTestCase;
+
+
+public class TestFunctionResolver
+extends AbstractTestCase
+{
+//----------------------------------------------------------------------------
+// Support Code
+//----------------------------------------------------------------------------
+
+ private static class MockStandardFunction
+ implements XPathFunction
+ {
+ public int _calls;
+
+ public Object evaluate(List args) throws XPathFunctionException
+ {
+ _calls++;
+ return null;
+ }
+ }
+
+
+//----------------------------------------------------------------------------
+// Test Cases
+//----------------------------------------------------------------------------
+
+ public void testSingleAbstractFunctionMaxRange() throws Exception
+ {
+ AbstractFunction<Object> fn = new AbstractFunction<Object>("foo", "bar");
+
+ FunctionResolver resolver = new FunctionResolver();
+ assertSame(resolver, resolver.addFunction(fn));
+
+ assertSame(fn, resolver.resolveFunction(new QName("foo", "bar"), 0));
+ assertSame(fn, resolver.resolveFunction(new QName("foo", "bar"), 1));
+ assertSame(fn, resolver.resolveFunction(new QName("foo", "bar"), 10));
+ }
+
+
+ public void testMultipleAbstractFunctionMaxRange() throws Exception
+ {
+ AbstractFunction<Object> fn1 = new AbstractFunction<Object>("foo", "bar");
+ AbstractFunction<Object> fn2 = new AbstractFunction<Object>("foo", "baz");
+
+ FunctionResolver resolver = new FunctionResolver()
+ .addFunction(fn1)
+ .addFunction(fn2);
+
+ assertSame(fn1, resolver.resolveFunction(new QName("foo", "bar"), 1));
+ assertSame(fn2, resolver.resolveFunction(new QName("foo", "baz"), 1));
+ }
+
+
+ public void testSingleAbstractFunctionMultiRange() throws Exception
+ {
+ AbstractFunction<Object> fn1 = new AbstractFunction<Object>("foo", "bar");
+ AbstractFunction<Object> fn2 = new AbstractFunction<Object>("foo", "bar", 1);
+ AbstractFunction<Object> fn3 = new AbstractFunction<Object>("foo", "bar", 2, 5);
+
+ FunctionResolver resolver = new FunctionResolver()
+ .addFunction(fn1)
+ .addFunction(fn2)
+ .addFunction(fn3);
+
+ assertSame(fn1, resolver.resolveFunction(new QName("foo", "bar"), 0));
+ assertSame(fn2, resolver.resolveFunction(new QName("foo", "bar"), 1));
+ assertSame(fn3, resolver.resolveFunction(new QName("foo", "bar"), 2));
+ assertSame(fn3, resolver.resolveFunction(new QName("foo", "bar"), 5));
+ assertSame(fn1, resolver.resolveFunction(new QName("foo", "bar"), 6));
+ }
+
+
+ public void testOverwriteOnAdd() throws Exception
+ {
+ AbstractFunction<Object> fn1 = new AbstractFunction<Object>("foo", "bar", 1);
+ AbstractFunction<Object> fn2 = new AbstractFunction<Object>("foo", "bar", 1);
+ AbstractFunction<Object> fn3 = new AbstractFunction<Object>("foo", "bar", 1);
+
+ FunctionResolver resolver = new FunctionResolver()
+ .addFunction(fn1)
+ .addFunction(fn2);
+
+ assertSame(fn2, resolver.resolveFunction(new QName("foo", "bar"), 1));
+
+ resolver.addFunction(fn3);
+ assertSame(fn3, resolver.resolveFunction(new QName("foo", "bar"), 1));
+ }
+
+
+ public void testSingleStandardFunctionMaxRange() throws Exception
+ {
+ MockStandardFunction xfn = new MockStandardFunction();
+
+ FunctionResolver resolver = new FunctionResolver()
+ .addFunction(xfn, new QName("foo", "bar"));
+
+ XPathFunction ret1 = resolver.resolveFunction(new QName("foo", "bar"), 0);
+ XPathFunction ret2 = resolver.resolveFunction(new QName("foo", "bar"), 0);
+ XPathFunction ret3 = resolver.resolveFunction(new QName("foo", "bar"), 0);
+
+ assertNotNull(ret1);
+ assertSame(ret1, ret2);
+ assertSame(ret1, ret3);
+
+ ret1.evaluate(Collections.EMPTY_LIST);
+ assertEquals(1, xfn._calls);
+ }
+
+
+ public void testSingleStandardFunctionMultiRange() throws Exception
+ {
+ MockStandardFunction xfn1 = new MockStandardFunction();
+ MockStandardFunction xfn2 = new MockStandardFunction();
+ MockStandardFunction xfn3 = new MockStandardFunction();
+
+ FunctionResolver resolver = new FunctionResolver()
+ .addFunction(xfn1, new QName("foo", "bar"))
+ .addFunction(xfn2, new QName("foo", "bar"), 1)
+ .addFunction(xfn3, new QName("foo", "bar"), 2, 5);
+
+ resolver.resolveFunction(new QName("foo", "bar"), 0).evaluate(Collections.EMPTY_LIST);
+ assertEquals(1, xfn1._calls);
+ assertEquals(0, xfn2._calls);
+ assertEquals(0, xfn3._calls);
+
+ resolver.resolveFunction(new QName("foo", "bar"), 1).evaluate(Collections.EMPTY_LIST);
+ assertEquals(1, xfn1._calls);
+ assertEquals(1, xfn2._calls);
+ assertEquals(0, xfn3._calls);
+
+ resolver.resolveFunction(new QName("foo", "bar"), 2).evaluate(Collections.EMPTY_LIST);
+ assertEquals(1, xfn1._calls);
+ assertEquals(1, xfn2._calls);
+ assertEquals(1, xfn3._calls);
+
+ resolver.resolveFunction(new QName("foo", "bar"), 5).evaluate(Collections.EMPTY_LIST);
+ assertEquals(1, xfn1._calls);
+ assertEquals(1, xfn2._calls);
+ assertEquals(2, xfn3._calls);
+
+ resolver.resolveFunction(new QName("foo", "bar"), 6).evaluate(Collections.EMPTY_LIST);
+ assertEquals(2, xfn1._calls);
+ assertEquals(1, xfn2._calls);
+ assertEquals(2, xfn3._calls);
+ }
+
+
+ public void testUnresolvedFunctions() throws Exception
+ {
+ FunctionResolver resolver = new FunctionResolver()
+ .addFunction(new AbstractFunction<Object>("foo", "bar", 1))
+ .addFunction(new AbstractFunction<Object>("fizz", "buzz", 1))
+ .addFunction(new AbstractFunction<Object>("fizz", "buzz", 2));
+
+ assertNull(resolver.resolveFunction(new QName("f", "b"), 1));
+ assertNull(resolver.resolveFunction(new QName("foo", "bar"), 2));
+ assertNull(resolver.resolveFunction(new QName("fizz", "buzz"), 3));
+ }
+
+
+ public void testEqualsAndHashcode() throws Exception
+ {
+ AbstractFunction<Object> fn1 = new AbstractFunction<Object>("foo", "bar", 1);
+ AbstractFunction<Object> fn2 = new AbstractFunction<Object>("foo", "bar", 1, 5);
+ AbstractFunction<Object> fn3 = new AbstractFunction<Object>("foo", "baz");
+
+ FunctionResolver resolv1 = new FunctionResolver()
+ .addFunction(fn1);
+ FunctionResolver resolv2 = new FunctionResolver()
+ .addFunction(fn1);
+ FunctionResolver resolv3 = new FunctionResolver()
+ .addFunction(fn2);
+ FunctionResolver resolv4 = new FunctionResolver()
+ .addFunction(fn1)
+ .addFunction(fn2);
+ FunctionResolver resolv5 = new FunctionResolver()
+ .addFunction(fn1)
+ .addFunction(fn2);
+ FunctionResolver resolv6 = new FunctionResolver()
+ .addFunction(fn1)
+ .addFunction(fn2)
+ .addFunction(fn3);
+ FunctionResolver resolv7 = new FunctionResolver()
+ .addFunction(fn1)
+ .addFunction(fn2)
+ .addFunction(fn3);
+
+ // self and bogus
+ assertTrue(resolv1.equals(resolv1));
+ assertFalse(resolv1.equals(new Object()));
+ assertFalse(resolv1.equals(null));
+
+ // single definition
+ assertTrue(resolv1.equals(resolv2));
+ assertTrue(resolv2.equals(resolv1));
+
+ // multiple definitions, same QName
+ assertTrue(resolv4.equals(resolv5));
+ assertTrue(resolv5.equals(resolv4));
+
+ // multiple definitions, multiple QNames
+ assertTrue(resolv6.equals(resolv7));
+ assertTrue(resolv7.equals(resolv6));
+
+ // different arity ranges
+ assertFalse(resolv1.equals(resolv3));
+ assertFalse(resolv3.equals(resolv1));
+
+ // partial overlap
+ assertFalse(resolv1.equals(resolv4));
+ assertFalse(resolv4.equals(resolv1));
+
+ // hashcode - the different hashcodes are per test
+ assertTrue(resolv1.hashCode() == resolv2.hashCode());
+ assertTrue(resolv1.hashCode() != resolv7.hashCode());
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|