[prev in list] [next in list] [prev in thread] [next in thread]
List: xmlbeans-cvs
Subject: svn commit: r644141 - in
From: radup () apache ! org
Date: 2008-04-03 2:44:56
Message-ID: 20080403024456.D4E121A9832 () eris ! apache ! org
[Download RAW message or body]
Author: radup
Date: Wed Apr 2 19:44:56 2008
New Revision: 644141
URL: http://svn.apache.org/viewvc?rev=644141&view=rev
Log:
Added a tool to generate XPath pointing to a given cursor position in a document.
Added:
xmlbeans/trunk/src/tools/org/apache/xmlbeans/impl/xpathgen/
xmlbeans/trunk/src/tools/org/apache/xmlbeans/impl/xpathgen/XPathGenerationException.java
xmlbeans/trunk/src/tools/org/apache/xmlbeans/impl/xpathgen/XPathGenerator.java
Added: xmlbeans/trunk/src/tools/org/apache/xmlbeans/impl/xpathgen/XPathGenerationException.java
URL: http://svn.apache.org/viewvc/xmlbeans/trunk/src/tools/org/apache/xmlbeans/impl/xpathgen/XPathGenerationException.java?rev=644141&view=auto
==============================================================================
--- xmlbeans/trunk/src/tools/org/apache/xmlbeans/impl/xpathgen/XPathGenerationException.java \
(added)
+++ xmlbeans/trunk/src/tools/org/apache/xmlbeans/impl/xpathgen/XPathGenerationException.java \
Wed Apr 2 19:44:56 2008 @@ -0,0 +1,14 @@
+package org.apache.xmlbeans.impl.xpathgen;
+
+import org.apache.xmlbeans.XmlException;
+
+/**
+ * An exception thrown if the XPath generation process can't complete
+ */
+public class XPathGenerationException extends XmlException
+{
+ public XPathGenerationException(String m)
+ {
+ super(m);
+ }
+}
Added: xmlbeans/trunk/src/tools/org/apache/xmlbeans/impl/xpathgen/XPathGenerator.java
URL: http://svn.apache.org/viewvc/xmlbeans/trunk/src/tools/org/apache/xmlbeans/impl/xpathgen/XPathGenerator.java?rev=644141&view=auto
==============================================================================
--- xmlbeans/trunk/src/tools/org/apache/xmlbeans/impl/xpathgen/XPathGenerator.java \
(added)
+++ xmlbeans/trunk/src/tools/org/apache/xmlbeans/impl/xpathgen/XPathGenerator.java \
Wed Apr 2 19:44:56 2008 @@ -0,0 +1,208 @@
+package org.apache.xmlbeans.impl.xpathgen;
+
+import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlCursor.TokenType;
+
+import javax.xml.namespace.QName;
+import javax.xml.namespace.NamespaceContext;
+
+/**
+ * Generates an XPath String that points to a given position in an XML document
+ */
+public class XPathGenerator
+{
+ /**
+ * Generates an XPath pointing to the position in the document indicated by \
<code>node</code>. + * <p>If the <code>context</code> parameter is null, the \
XPath is absolute, otherwise the + * XPath will be relative to the position \
indicated by <code>context</code>.</p> + * <p>Note: the cursor position for the \
<code>node</code> parameter is not preserved</p> + * @param node the position in \
the document that the generated path will point to + * @param context the context \
node; the generated path will be relative to it if not null and if + * pointing \
to an element on the path from the document root to <code>node</code> + * @param \
nsctx a namespace context that will be used to obtain prefixes; a (non-default) + \
* namespace mapping must be available for all required namespace URIs + * @return \
the generated path as a <code>String</code> + * @throws XPathGenerationException \
if the path could not be generated: the cursor is in a bad + * position (like \
over a comment) or no prefix mapping was found for one of the namespace URIs + */
+ public static String generateXPath(XmlCursor node, XmlCursor context, \
NamespaceContext nsctx) + throws XPathGenerationException
+ {
+ if (node == null)
+ throw new IllegalArgumentException("Null node");
+ if (nsctx == null)
+ throw new IllegalArgumentException("Null namespace context");
+ TokenType tt = node.currentTokenType();
+ if (context != null && node.isAtSamePositionAs(context))
+ return ".";
+ switch (tt.intValue())
+ {
+ case TokenType.INT_ATTR:
+ QName name = node.getName();
+ node.toParent();
+ String pathToParent = generateInternal(node, context, nsctx);
+ return pathToParent + '/' + '@' + qnameToString(name, nsctx);
+ case TokenType.INT_NAMESPACE:
+ name = node.getName();
+ node.toParent();
+ pathToParent = generateInternal(node, context, nsctx);
+ String prefix = name.getLocalPart();
+ if (prefix.length() == 0)
+ return pathToParent + "/@xmlns";
+ else
+ return pathToParent + "/@xmlns:" + prefix;
+ case TokenType.INT_START:
+ case TokenType.INT_STARTDOC:
+ return generateInternal(node, context, nsctx);
+ case TokenType.INT_TEXT:
+ int nrOfTextTokens = countTextTokens(node);
+ node.toParent();
+ pathToParent = generateInternal(node, context, nsctx);
+ if (nrOfTextTokens == 0)
+ return pathToParent + "/text()";
+ else
+ return pathToParent + "/text()[position()=" + nrOfTextTokens + \
']'; + default:
+ throw new XPathGenerationException("Cannot generate XPath for cursor \
position: " + + tt.toString());
+ }
+ }
+
+ private static String generateInternal(XmlCursor node, XmlCursor context, \
NamespaceContext nsctx) + throws XPathGenerationException
+ {
+ if (node.isStartdoc())
+ return "";
+ if (context != null && node.isAtSamePositionAs(context))
+ return ".";
+ assert node.isStart();
+ QName name = node.getName();
+ XmlCursor d = node.newCursor();
+ if (!node.toParent())
+ return "/" + name;
+ int elemIndex = 0, i = 1;
+ node.push();
+ if (!node.toChild(name))
+ throw new IllegalStateException("Must have at least one child with name: \
" + name); + do
+ {
+ if (node.isAtSamePositionAs(d))
+ elemIndex = i;
+ else
+ i++;
+ } while (node.toNextSibling(name));
+ node.pop();
+ d.dispose();
+ String pathToParent = generateInternal(node, context, nsctx);
+ return i == 1 ? pathToParent + '/' + qnameToString(name, nsctx) :
+ pathToParent + '/' + qnameToString(name, nsctx) + '[' + elemIndex + ']';
+ }
+
+ private static String qnameToString(QName qname, NamespaceContext ctx)
+ throws XPathGenerationException
+ {
+ String localName = qname.getLocalPart();
+ String uri = qname.getNamespaceURI();
+ if (uri.length() == 0)
+ return localName;
+ String prefix = qname.getPrefix();
+ if (prefix != null && prefix.length() > 0)
+ {
+ // Try to use the same prefix if it maps to the right URI
+ String mappedUri = ctx.getNamespaceURI(prefix);
+ if (uri.equals(mappedUri))
+ return prefix + ':' + localName;
+ }
+ // The prefix is not specified, or it is not mapped to the right URI
+ prefix = ctx.getPrefix(uri);
+ if (prefix == null)
+ throw new XPathGenerationException("Could not obtain a prefix for URI: " \
+ uri); + if (prefix.length() == 0)
+ throw new XPathGenerationException("Can not use default prefix in XPath \
for URI: " + uri); + return prefix + ':' + localName;
+ }
+
+ /**
+ * Computes how many text nodes the
+ * @param c the position in the document
+ * @return how many text nodes occur before the position determined by \
<code>c</code> + */
+ private static int countTextTokens(XmlCursor c)
+ {
+ int k = 0;
+ int l = 0;
+ XmlCursor d = c.newCursor();
+ c.push();
+ c.toParent();
+ TokenType tt = c.toFirstContentToken();
+ while (!tt.isEnd())
+ {
+ if (tt.isText())
+ {
+ if (c.comparePosition(d) > 0)
+ // We have moved after the initial position
+ l++;
+ else
+ k++;
+ }
+ else if (tt.isStart())
+ c.toEndToken();
+ tt = c.toNextToken();
+ }
+ c.pop();
+ return l == 0 ? 0 : k;
+ }
+
+ public static void main(String[] args) throws org.apache.xmlbeans.XmlException
+ {
+ String xml =
+ "<root>\n" +
+ "<ns:a xmlns:ns=\"http://a.com\"><b \
foo=\"value\">text1<c/>text2<c/>text3<c>text</c>text4</b></ns:a>\n" + + \
"</root>"; + NamespaceContext ns = new NamespaceContext() {
+ public String getNamespaceURI(String prefix)
+ {
+ if ("ns".equals(prefix))
+ return "http://a.com";
+ else
+ return null;
+ }
+ public String getPrefix(String namespaceUri)
+ {
+ return null;
+ }
+ public java.util.Iterator getPrefixes(String namespaceUri)
+ {
+ return null;
+ }
+ };
+ XmlCursor c = org.apache.xmlbeans.XmlObject.Factory.parse(xml).newCursor();
+ c.toFirstContentToken(); // on <root>
+ c.toFirstContentToken(); // on <a>
+ c.toFirstChild(); // on <b>
+ c.toFirstChild(); // on <c>
+ c.push(); System.out.println(generateXPath(c, null, ns)); c.pop();
+ c.toNextSibling();
+ c.toNextSibling(); // on the last <c>
+ c.push(); System.out.println(generateXPath(c, null, ns)); c.pop();
+ XmlCursor d = c.newCursor();
+ d.toParent();
+ c.push(); System.out.println(generateXPath(c, d, ns)); c.pop();
+ d.toParent();
+ c.push(); System.out.println(generateXPath(c, d, ns)); c.pop();
+ c.toFirstContentToken(); // on text content of the last <c>
+ c.push(); System.out.println(generateXPath(c, d, ns)); c.pop();
+ c.toParent();
+ c.toPrevToken(); // on text content before the last <c>
+ c.push(); System.out.println(generateXPath(c, d, ns)); c.pop();
+ c.toParent(); // on <b>
+ c.push(); System.out.println(generateXPath(c, d, ns)); c.pop();
+ c.toFirstAttribute(); // on the "foo" attribute
+ c.push(); System.out.println(generateXPath(c, d, ns)); c.pop();
+ c.toParent();
+ c.toParent();
+ c.toNextToken(); // on the "xmlns:ns" attribute
+ c.push(); System.out.println(generateXPath(c, d, ns)); c.pop();
+ c.push(); System.out.println(generateXPath(c, null, ns)); c.pop();
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xmlbeans.apache.org
For additional commands, e-mail: commits-help@xmlbeans.apache.org
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic