You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vxquery.apache.org by ti...@apache.org on 2010/04/15 03:00:50 UTC
svn commit: r934257 - in
/incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery:
datamodel/NodeEqComparator.java functions/builtin-functions.xml
runtime/functions/FnDeepEqualIterator.java
Author: tillw
Date: Thu Apr 15 01:00:49 2010
New Revision: 934257
URL: http://svn.apache.org/viewvc?rev=934257&view=rev
Log:
- added implementation for fn:deep-equal
Added:
incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/datamodel/NodeEqComparator.java
incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/runtime/functions/FnDeepEqualIterator.java
Modified:
incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/functions/builtin-functions.xml
Added: incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/datamodel/NodeEqComparator.java
URL: http://svn.apache.org/viewvc/incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/datamodel/NodeEqComparator.java?rev=934257&view=auto
==============================================================================
--- incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/datamodel/NodeEqComparator.java (added)
+++ incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/datamodel/NodeEqComparator.java Thu Apr 15 01:00:49 2010
@@ -0,0 +1,209 @@
+package org.apache.vxquery.datamodel;
+
+import org.apache.vxquery.collations.CodepointCollation;
+import org.apache.vxquery.collations.Collation;
+import org.apache.vxquery.datamodel.atomic.compare.ComparisonUtils;
+import org.apache.vxquery.datamodel.atomic.compare.ValueEqComparator;
+import org.apache.vxquery.exceptions.SystemException;
+import org.apache.vxquery.runtime.RuntimeControlBlock;
+import org.apache.vxquery.runtime.base.CloseableIterator;
+
+public final class NodeEqComparator {
+ public static final NodeEqComparator INSTANCE = new NodeEqComparator();
+
+ private Collation collation;
+
+ private NodeEqComparator() {
+ this(CodepointCollation.INSTANCE);
+ }
+
+ private NodeEqComparator(Collation collation) {
+ this.collation = collation;
+ }
+
+ public static NodeEqComparator get(Collation collation) {
+ if (collation == null || collation == CodepointCollation.INSTANCE) {
+ return INSTANCE;
+ } else {
+ return new NodeEqComparator(collation);
+ }
+ }
+
+ public boolean compareDocument(XDMNode n1, XDMNode n2) {
+ throw new UnsupportedOperationException(); // TODO
+ }
+
+ public boolean compareElement(XDMNode n1, XDMNode n2, RuntimeControlBlock rcb) throws SystemException {
+ if (!compareNodeName(n1, n2)) {
+ return false;
+ }
+ // TODO check and compare types - right now everything is untyped
+ if (n1.hasAttributes()) {
+ if (!n2.hasAttributes() || !compareAttributes(n1, n2, rcb)) {
+ return false;
+ }
+ } else if (n2.hasAttributes()) {
+ return false;
+ }
+
+ CloseableIterator ci1 = n1.getChildren();
+ CloseableIterator ci2 = n2.getChildren();
+ Object child1;
+ while ((child1 = ci1.next()) != null) {
+ // TODO need to skip everything that's not an element or a text node
+ Object child2 = ci2.next();
+ if (child2 == null) {
+ ci1.close();
+ ci2.close();
+ return false;
+ }
+ XDMNode chn1 = (XDMNode) child1;
+ XDMNode chn2 = (XDMNode) child2;
+ if (chn1.getDMOKind() != chn2.getDMOKind()) {
+ ci1.close();
+ ci2.close();
+ return false;
+ }
+ switch (chn1.getDMOKind()) {
+ case ELEMENT_NODE:
+ if (!compareElement(chn1, chn2, rcb)) {
+ ci1.close();
+ ci2.close();
+ return false;
+ }
+ break;
+ case TEXT_NODE:
+ if (!compareText(chn1, chn2)) {
+ ci1.close();
+ ci2.close();
+ return false;
+ }
+ break;
+ case COMMENT_NODE:
+ break;
+ default:
+ throw new IllegalStateException(chn1.getDMOKind().toString());
+ }
+ }
+ ci1.close();
+ boolean result = ci2.next() == null;
+ ci2.close();
+
+ return result;
+ }
+
+ private boolean compareAttributes(XDMNode n1, XDMNode n2, RuntimeControlBlock rcb) throws SystemException {
+ CloseableIterator ci1 = n1.getAttributes();
+ CloseableIterator ci2 = null;
+ Object o1 = ci1.next();
+ int c1 = 0;
+ int c2 = 0;
+ while (o1 != null) {
+ ++c1;
+ if (ci2 != null) {
+ ci2.close();
+ }
+ c2 = 0;
+ ci2 = n2.getAttributes();
+ Object o2 = ci2.next();
+ while (o2 != null) {
+ ++c2;
+ if (compareAttribute((XDMNode) o1, (XDMNode) o2, rcb)) {
+ break;
+ }
+ o2 = ci2.next();
+ }
+ if (o2 == null) {
+ ci1.close();
+ ci2.close();
+ return false;
+ }
+ o1 = ci1.next();
+ }
+ ci1.close();
+ if (ci2 != null) {
+ while (ci2.next() != null) {
+ if (++c2 > c1) {
+ ci2.close();
+ return false;
+ }
+ }
+ }
+ ci2.close();
+ return true;
+ }
+
+ public boolean compareAttribute(XDMNode n1, XDMNode n2, RuntimeControlBlock rcb) throws SystemException {
+ if (!compareNodeName(n1, n2)) {
+ return false;
+ }
+ XDMValue v1 = n1.getTypedValue();
+ XDMValue v2 = n2.getTypedValue();
+ if (v1.getDMOKind() != v2.getDMOKind()) {
+ return false;
+ } else if (v1.getDMOKind() == DMOKind.SEQUENCE) {
+ CloseableIterator ci1 = ((XDMSequence) v1).createItemIterator();
+ CloseableIterator ci2 = ((XDMSequence) v2).createItemIterator();
+ Object o1 = ci1.next();
+ while (o1 != null) {
+ Object o2 = ci2.next();
+ if (o2 == null || !compareAtomic((XDMAtomicValue) o1, (XDMAtomicValue) o2, rcb)) {
+ ci1.close();
+ ci2.close();
+ return false;
+ }
+ o1 = ci1.next();
+ }
+ final boolean result = ci2.next() == null ? true : false;
+ ci1.close();
+ ci2.close();
+ return result;
+ }
+ return compareAtomic((XDMAtomicValue) v1, (XDMAtomicValue) v2, rcb);
+ }
+
+ public boolean compareNamespace(XDMNode n1, XDMNode n2) {
+ throw new UnsupportedOperationException(); // TODO
+ }
+
+ public boolean compareProcessingInstruction(XDMNode n1, XDMNode n2) {
+ assert n1.getDMOKind() == DMOKind.PI_NODE;
+ assert n2.getDMOKind() == DMOKind.PI_NODE;
+ return compareNodeName(n1, n2) && compareStringValue(n1, n2);
+ }
+
+ public boolean compareComment(XDMNode n1, XDMNode n2) {
+ assert n1.getDMOKind() == DMOKind.COMMENT_NODE;
+ assert n2.getDMOKind() == DMOKind.COMMENT_NODE;
+ return compareStringValue(n1, n2);
+ }
+
+ public boolean compareText(XDMNode n1, XDMNode n2) {
+ assert n1.getDMOKind() == DMOKind.TEXT_NODE;
+ assert n2.getDMOKind() == DMOKind.TEXT_NODE;
+ return compareStringValue(n1, n2);
+ }
+
+ private boolean compareStringValue(XDMNode n1, XDMNode n2) {
+ return collation.getComparator().compare(n1.getStringValue(), n2.getStringValue()) == 0;
+ }
+
+ private boolean compareNodeName(XDMNode n1, XDMNode n2) {
+ try {
+ return ValueEqComparator.INSTANCE.compareQName(n1.getNodeName(), n2.getNodeName());
+ } catch (SystemException e) {
+ // this should be impossible
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public boolean compareAtomic(XDMAtomicValue a1, XDMAtomicValue a2, RuntimeControlBlock rcb) throws SystemException {
+ Boolean result = ComparisonUtils.valueCompare(rcb, a1, a2, ValueEqComparator.INSTANCE, collation);
+ if (result == null) {
+ return false;
+ } else {
+ // TODO if both are NaN we need to return true as well
+ return result;
+ }
+ }
+}
\ No newline at end of file
Modified: incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/functions/builtin-functions.xml
URL: http://svn.apache.org/viewvc/incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/functions/builtin-functions.xml?rev=934257&r1=934256&r2=934257&view=diff
==============================================================================
--- incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/functions/builtin-functions.xml (original)
+++ incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/functions/builtin-functions.xml Thu Apr 15 01:00:49 2010
@@ -224,14 +224,16 @@
<param name="parameter1" type="item()*"/>
<param name="parameter2" type="item()*"/>
<return type="xs:boolean"/>
+ <runtime class="org.apache.vxquery.runtime.functions.FnDeepEqualIterator"/>
</function>
- <!-- fn:deep-equal($parameter1 as item()*, $parameter2 as item()*, $collation as string) as xs:boolean -->
+ <!-- fn:deep-equal($parameter1 as item()*, $parameter2 as item()*, $collation as xs:string) as xs:boolean -->
<function name="fn:deep-equal">
<param name="parameter1" type="item()*"/>
<param name="parameter2" type="item()*"/>
<param name="collation" type="xs:string"/>
<return type="xs:boolean"/>
+ <runtime class="org.apache.vxquery.runtime.functions.FnDeepEqualIterator"/>
</function>
<!-- fn:default-collation() as xs:string -->
Added: incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/runtime/functions/FnDeepEqualIterator.java
URL: http://svn.apache.org/viewvc/incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/runtime/functions/FnDeepEqualIterator.java?rev=934257&view=auto
==============================================================================
--- incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/runtime/functions/FnDeepEqualIterator.java (added)
+++ incubator/vxquery/trunk/vxquery/src/main/java/org/apache/vxquery/runtime/functions/FnDeepEqualIterator.java Thu Apr 15 01:00:49 2010
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.vxquery.runtime.functions;
+
+import org.apache.vxquery.collations.Collation;
+import org.apache.vxquery.context.StaticContext;
+import org.apache.vxquery.datamodel.NodeEqComparator;
+import org.apache.vxquery.datamodel.XDMAtomicValue;
+import org.apache.vxquery.datamodel.XDMItem;
+import org.apache.vxquery.datamodel.XDMNode;
+import org.apache.vxquery.datamodel.atomic.StringValue;
+import org.apache.vxquery.exceptions.ErrorCode;
+import org.apache.vxquery.exceptions.SystemException;
+import org.apache.vxquery.functions.Function;
+import org.apache.vxquery.runtime.CallStackFrame;
+import org.apache.vxquery.runtime.RegisterAllocator;
+import org.apache.vxquery.runtime.RuntimeControlBlock;
+import org.apache.vxquery.runtime.base.AbstractEagerlyEvaluatedFunctionIterator;
+import org.apache.vxquery.runtime.base.RuntimeIterator;
+
+public class FnDeepEqualIterator extends AbstractEagerlyEvaluatedFunctionIterator {
+ public FnDeepEqualIterator(RegisterAllocator rAllocator, Function fn, RuntimeIterator[] arguments, StaticContext ctx) {
+ super(rAllocator, fn, arguments, ctx);
+ }
+
+ @Override
+ public Object evaluateEagerly(CallStackFrame frame) throws SystemException {
+ final NodeEqComparator comparator = getComparator(frame);
+
+ final RuntimeIterator left = arguments[0];
+ final RuntimeIterator right = arguments[1];
+ left.open(frame);
+ right.open(frame);
+
+ final RuntimeControlBlock rcb = frame.getRuntimeControlBlock();
+ Object lObj;
+ while ((lObj = left.next(frame)) != null) {
+ Object rObj = right.next(frame);
+ if (rObj == null) {
+ left.close(frame);
+ right.close(frame);
+ return rcb.getAtomicValueFactory().createBoolean(false);
+ }
+ XDMItem lItem = (XDMItem) lObj;
+ XDMItem rItem = (XDMItem) rObj;
+ if (lItem.getDMOKind() != rItem.getDMOKind()) {
+ left.close(frame);
+ right.close(frame);
+ return rcb.getAtomicValueFactory().createBoolean(false);
+ }
+ if (!itemsEqual(lItem, rItem, comparator, rcb)) {
+ return rcb.getAtomicValueFactory().createBoolean(false);
+ }
+ }
+ left.close(frame);
+ final boolean result = right.next(frame) == null;
+ right.close(frame);
+ return rcb.getAtomicValueFactory().createBoolean(result);
+ }
+
+ private boolean itemsEqual(XDMItem lItem, XDMItem rItem, final NodeEqComparator comparator,
+ final RuntimeControlBlock rcb) throws SystemException {
+ switch (lItem.getDMOKind()) {
+ case ATOMIC_VALUE:
+ return comparator.compareAtomic((XDMAtomicValue) lItem, (XDMAtomicValue) rItem, rcb);
+ case DOCUMENT_NODE:
+ return comparator.compareDocument((XDMNode) lItem, (XDMNode) rItem);
+ case ELEMENT_NODE:
+ return comparator.compareElement((XDMNode) lItem, (XDMNode) rItem, rcb);
+ case ATTRIBUTE_NODE:
+ return comparator.compareAttribute((XDMNode) lItem, (XDMNode) rItem, rcb);
+ case PI_NODE:
+ return comparator.compareProcessingInstruction((XDMNode) lItem, (XDMNode) rItem);
+ case TEXT_NODE:
+ return comparator.compareText((XDMNode) lItem, (XDMNode) rItem);
+ case COMMENT_NODE:
+ return comparator.compareComment((XDMNode) lItem, (XDMNode) rItem);
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private NodeEqComparator getComparator(final CallStackFrame frame) throws SystemException {
+ final RuntimeControlBlock rcb = frame.getRuntimeControlBlock();
+ final Collation collation;
+ if (arguments.length == 3) {
+ final RuntimeIterator collationIterator = arguments[2];
+ final StringValue collationName = (StringValue) collationIterator.evaluateEagerly(frame);
+ collation = rcb.getDynamicContext().getStaticContext().lookupCollation(
+ collationName.getStringValue().toString());
+ if (collation == null) {
+ throw new SystemException(ErrorCode.FOCH0002);
+ }
+ } else {
+ collation = rcb.getDefaultCollation();
+ }
+ return NodeEqComparator.get(collation);
+ }
+
+}