Permalink
Browse files

Fixes #120 - clone of JaxenComplied instance.

Now it does a Copy-Constructor clone instead of changing final instance fields.
  • Loading branch information...
1 parent 250d723 commit 5497a5a66db770644619318c8be86d563134f9a8 @rolfl rolfl committed with rolfl Jun 8, 2013
@@ -156,6 +156,16 @@ public JaxenCompiled(String expression, Filter<T> filter,
xPath.setVariableContext(this);
}
+ /**
+ * Make a copy-constructor available to the clone() method.
+ * This is simpler than trying to do a deep clone anyway.
+ *
+ * @param toclone The JaxenCompiled instance to clone
+ */
+ private JaxenCompiled(JaxenCompiled<T> toclone) {
+ this(toclone.getExpression(), toclone.getFilter(), toclone.getVariables(), toclone.getNamespaces());
+ }
+
@Override
public String translateNamespacePrefixToUri(String prefix) {
return getNamespace(prefix).getURI();
@@ -201,5 +211,14 @@ protected Object evaluateRawFirst(Object context) {
"Unable to evaluate expression. See cause", e);
}
}
+
+ @Override
+ public JaxenCompiled<T> clone() {
+ // Use a copy-constructor instead of a deep clone.
+ // we have a couple of final variables on this class that we cannot share
+ // between instances, and the Jaxen xpath variable is pretty complicated to reconstruct
+ // anyway. Easier to just reconstruct it.
+ return new JaxenCompiled<T>(this);
+ }
}
@@ -88,6 +88,21 @@ public int compare(Namespace ns1, Namespace ns2) {
private static final NamespaceComparator NSSORT = new NamespaceComparator();
+ /**
+ * Utility method to find a Namespace that has a given URI, and return the prefix.
+ * @param uri the URI to search for
+ * @param nsa the array of namespaces to search through
+ * @return the prefix of the namespace
+ */
+ private static final String getPrefixForURI(final String uri, final Namespace[] nsa) {
+ for (final Namespace ns : nsa) {
+ if (ns.getURI().equals(uri)) {
+ return ns.getPrefix();
+ }
+ }
+ throw new IllegalStateException("No namespace defined with URI " + uri);
+ }
+
private final Map<String, Namespace> xnamespaces = new HashMap<String, Namespace>();
// Not final to support cloning.
private Map<String, Map<String, Object>> xvariables = new HashMap<String, Map<String, Object>>();
@@ -309,6 +324,28 @@ public Object setVariable(String qname, Object value) {
return setVariable(qname, Namespace.NO_NAMESPACE, value);
}
+ /**
+ * utility method that allows descendant classes to access the variables
+ * that were set on this expression, in a format that can be used in a constructor (qname/value).
+ * @return the variables set on this instance.
+ */
+ protected Map<String,Object> getVariables() {
+ HashMap<String,Object> vars = new HashMap<String, Object>();
+ Namespace[] nsa = getNamespaces();
+ for (Map.Entry<String, Map<String,Object>> ue : xvariables.entrySet()) {
+ final String uri = ue.getKey();
+ final String pfx = getPrefixForURI(uri, nsa);
+ for (Map.Entry<String, Object> ve : ue.getValue().entrySet()) {
+ if ("".equals(pfx)) {
+ vars.put(ve.getKey(), ve.getValue());
+ } else {
+ vars.put(pfx + ":" + ve.getKey(), ve.getValue());
+ }
+ }
+ }
+ return vars;
+ }
+
@Override
public final Filter<T> getFilter() {
return xfilter;
@@ -753,6 +753,42 @@ public void testClone() {
}
@Test
+ public void testCloneVariables() {
+ List<Element> lst = null;
+ HashMap<String,Object> vars = new HashMap<String,Object>();
+ vars.put("vns:vname", "1");
+ Namespace vns = Namespace.getNamespace("vns", "http://jdom.org/xpath_variable_namespace");
+ XPathExpression<Element> xpathhc = XPathFactory.instance().compile(
+ "/main/child[1]", Filters.element());
+ lst = xpathhc.evaluate(doc);
+ assertTrue(1 == lst.size());
+ assertTrue(child1emt == lst.get(0));
+
+ XPathExpression<Element> xpath = XPathFactory.instance().compile(
+ "/main/child[position() = $vns:vname]", Filters.element(), vars, vns);
+ lst = xpath.evaluate(doc);
+ assertTrue(1 == lst.size());
+ assertTrue(child1emt == lst.get(0));
+ xpath.setVariable("vns:vname", "2");
+ assertTrue("2" == xpath.getVariable("vname", vns));
+ lst = xpath.evaluate(doc);
+ assertTrue(1 == lst.size());
+ assertTrue(child2emt == lst.get(0));
+
+ XPathExpression<Element> cloned = xpath.clone();
+ lst = cloned.evaluate(doc);
+ assertTrue(1 == lst.size());
+ assertTrue(child2emt == lst.get(0));
+
+ cloned.setVariable("vns:vname", "1");
+ assertTrue("2" == xpath.getVariable("vname", vns));
+ assertTrue("1" == cloned.getVariable("vname", vns));
+ lst = cloned.evaluate(doc);
+ assertTrue(1 == lst.size());
+ assertTrue(child1emt == lst.get(0));
+ }
+
+ @Test
public void testSelectDocumentDoc() {
checkXPath("/", doc, mainvalue, doc);
}

0 comments on commit 5497a5a

Please sign in to comment.