/* * eXist Open Source Native XML Database * Copyright (C) 2006-2009 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id$ */ package org.exist.xquery.modules.xmldiff; import org.apache.log4j.Logger; import org.custommonkey.xmlunit.Diff; import org.exist.dom.QName; import org.exist.storage.serializers.Serializer; import org.exist.xquery.*; import org.exist.xquery.value.*; import org.xml.sax.SAXException; import javax.xml.transform.OutputKeys; import java.util.Properties; /** * @author Pierrick Brihaye <pierrick.brihaye@free.fr> */ public class Compare extends Function { private static final Logger logger = Logger.getLogger(Compare.class); private final static Properties OUTPUT_PROPERTIES = new Properties(); static { OUTPUT_PROPERTIES.setProperty(OutputKeys.INDENT, "no"); OUTPUT_PROPERTIES.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); } public final static FunctionSignature signature = new FunctionSignature( new QName("compare", XmlDiffModule.NAMESPACE_URI, XmlDiffModule.PREFIX), "Returns true() if the two node sets $node-set-1 and $node-set-2 are equal, otherwise false()", new SequenceType[] { new FunctionParameterSequenceType("node-set-1", Type.NODE, Cardinality.ZERO_OR_MORE, "the first node set"), new FunctionParameterSequenceType("node-set-2", Type.NODE, Cardinality.ZERO_OR_MORE, "the second node set") }, new FunctionReturnSequenceType(Type.BOOLEAN, Cardinality.ZERO_OR_ONE, "true() if the two node sets $node-set-1 and $node-set-2 are equal, otherwise false()")); public Compare(XQueryContext context) { super(context, signature); } /* * (non-Javadoc) * * @see org.exist.xquery.BasicFunction#eval(org.exist.xquery.value.Sequence[], * org.exist.xquery.value.Sequence) */ public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException { if (context.getProfiler().isEnabled()) { context.getProfiler().start(this); context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies())); if (contextSequence != null) context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence); if (contextItem != null) context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence()); } Expression arg1 = getArgument(0); Sequence s1 = arg1.eval(contextSequence, contextItem); Expression arg2 = getArgument(1); context.pushDocumentContext(); Sequence s2 = arg2.eval(contextSequence, contextItem); context.popDocumentContext(); if (s1.isEmpty()) { return BooleanValue.valueOf(s2.isEmpty()); } else if (s2.isEmpty()) { return BooleanValue.valueOf(s1.isEmpty()); } Sequence result = null; StringBuffer v1 = new StringBuffer(); StringBuffer v2 = new StringBuffer(); try { if (s1.hasMany()){ for (int i = 0; i < s1.getItemCount(); i++) { v1.append(serialize((NodeValue) s1.itemAt(i))); } } else { v1.append(serialize((NodeValue) s1.itemAt(0))); } if (s2.hasMany()) { for (int i = 0; i < s2.getItemCount(); i++) { v2.append(serialize((NodeValue) s2.itemAt(i))); } } else { v2.append(serialize((NodeValue) s2.itemAt(0))); } Diff d = new Diff(v1.toString(), v2.toString()); boolean identical = d.identical(); if (!identical) { logger.warn("Diff result: " + d.toString()); } result = new BooleanValue(identical); } catch (Exception e) { throw new XPathException(this, "An exception occurred while serializing node " + "for comparison: " + e.getMessage(), e); } if (context.getProfiler().isEnabled()) context.getProfiler().end(this, "", result); return result; } private String serialize(NodeValue node) throws SAXException { Serializer serializer = context.getBroker().getSerializer(); serializer.reset(); serializer.setProperties(OUTPUT_PROPERTIES); return serializer.serialize(node); } }