diff --git a/mozilla/extensions/transformiix/source/xslt/util/Makefile b/mozilla/extensions/transformiix/source/xslt/util/Makefile index cb720128aa7..0b4058947e1 100644 --- a/mozilla/extensions/transformiix/source/xslt/util/Makefile +++ b/mozilla/extensions/transformiix/source/xslt/util/Makefile @@ -1,10 +1,40 @@ -ALL_OBJS = NodeStack.o - -INCLUDE_PATH = -I../../base -I../..expr -I../../xml -I../../xml/dom +ROOT = ../.. +BASE = $(ROOT)/base +XPATH = $(ROOT)/xpath +XML = $(ROOT)/xml +XML_UTIL = $(XML)/util +DOM = $(XML)/dom +XSLT = $(ROOT)/xslt + +ALL_OBJS = \ + NodeSorter.o \ + NodeStack.o + + + +INCLUDE_PATH = -I. \ + -I$(BASE) \ + -I$(XPATH) \ + -I$(XML) \ + -I$(XML_UTIL) \ + -I$(DOM) \ + -I$(XSLT) target: $(ALL_OBJS) +NodeSorter.o: NodeSorter.h NodeSorter.cpp + $(CC) $(INCLUDE_PATH) -c NodeSorter.cpp + NodeStack.o: NodeStack.h NodeStack.cpp $(CC) $(INCLUDE_PATH) -c NodeStack.cpp + + + + + + + + + diff --git a/mozilla/extensions/transformiix/source/xslt/util/NodeSorter.cpp b/mozilla/extensions/transformiix/source/xslt/util/NodeSorter.cpp new file mode 100644 index 00000000000..373bd95994f --- /dev/null +++ b/mozilla/extensions/transformiix/source/xslt/util/NodeSorter.cpp @@ -0,0 +1,300 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is XSL:P XSLT processor. + * + * The Initial Developer of the Original Code is Keith Visco. + * Portions created by Keith Visco (C) 1999-2000 Keith Visco. + * All Rights Reserved.. + * + * Contributor(s): + * + * Keith Visco, kvisco@ziplink.net + * -- original author. + * + * $Id: NodeSorter.cpp,v 1.1 2000-04-12 10:55:52 kvisco%ziplink.net Exp $ + */ + + + +#include "NodeSorter.h" + +/* + * Sorts Nodes as specified by the W3C XSLT 1.0 Recommendation + */ + + +//-- static variables +const String NodeSorter::DEFAULT_LANG = "en"; +const String NodeSorter::ASCENDING_ORDER = "ascending"; +const String NodeSorter::DESCENDING_ORDER = "descending"; +const String NodeSorter::TEXT_TYPE = "text"; +const String NodeSorter::NUMBER_TYPE = "number"; + +/** + * Sorts the given Node Array using this XSLSort's properties as a + * basis for the sort + * @param nodes the Array of nodes to sort + * @param pState the ProcessorState to evaluate the Select pattern with + * @return the a new Array of sorted nodes + **/ +void NodeSorter::sort + (NodeSet* nodes, Element* sortElement, Node* context, ProcessorState* ps) +{ + + if ((!nodes) || (!sortElement)) return; + + + // Build sortKeys table + NamedMap keyHash; + + //-- create a new pointer to sortElement, we will use this + //-- to handle multiple sort keys + //-- (ie. xsl:sort siblings of sortElement) + Element* xslSort = sortElement; + + + String lang(DEFAULT_LANG); + String order(ASCENDING_ORDER); + String datatype(TEXT_TYPE); + + ExprParser exprParser; //-- I'll make this static soon + Expr* selectExpr = ps->getExpr(xslSort->getAttribute(SELECT_ATTR)); + + //avt = exprParser.createAttributeValueTemplate(attValue); + //ExprResult* exprResult = avt->evaluate(context,ps); + //exprResult->stringValue(result); + //delete exprResult; + //delete avt; + + AttributeValueTemplate* avt = 0; + ExprResult* exprResult = 0; + + // get lang (Not Yet Implemented) + // avt = xslSort.getAttributeAsAVT(XSLSort.LANG_ATTR); + // if (avt) lang = avt.evaluate(context, pState); + + // Get Order + DOMString attValue = xslSort->getAttribute(ORDER_ATTR); + if (attValue.length() > 0) { + avt = exprParser.createAttributeValueTemplate(attValue); + exprResult = avt->evaluate(context, ps); + order.clear(); + exprResult->stringValue(order); + //-- clean up + delete exprResult; + delete avt; + avt = 0; + } + + + // Get DataType (Not Yet Implemented) + // avt = xslSort.getAttributeAsAVT(XSLSort.DATA_TYPE_ATTR); + // if (avt) dataType = avt.evaluate(context, pState); + + MBool ascending = order.isEqual(ASCENDING_ORDER); + + NodeSet noKeyBucket; + // Build hash table of sort keys + for (int i = 0; i < nodes->size(); i++) { + Node* node = nodes->get(i); + String* sortKey = new String(); + exprResult = selectExpr->evaluate(node, ps); + if ((!exprResult) || (exprResult->getResultType() != ExprResult::NODESET)) { + //-- should we flag this as an error? + //String err("Error in select expr of xslt sort element, expecting NodeSet as result of: "); + //selectExpr->toString(err); + //ps->recieveError(err); + //delete exprResult; + //continue; + } + else { + NodeSet* resultNodes = (NodeSet*)exprResult; + if (resultNodes->size() > 0) { + XMLDOMUtils::getNodeValue(resultNodes->get(0), sortKey); + } + } + + if (sortKey->length() == 0) noKeyBucket.add(node); + else { + NodeSet* bucket = (NodeSet*) keyHash.get(*sortKey); + if (!bucket) { + bucket = new NodeSet(); + bucket->add(node); + keyHash.put(*sortKey, bucket); + } + else bucket->add(node); + } + + delete exprResult; + } + + // Return sorted Nodes + StringList* list = keyHash.keys(); + int nbrKeys = list->getLength(); + String** keys = new String*[nbrKeys]; + StringListIterator* iter = list->iterator(); + int c = 0; + while (iter->hasNext()) { + keys[c++] = iter->next(); + } + delete iter; + + //-- sort keys + sortKeys(keys, nbrKeys, ascending, datatype, lang); + + nodes->clear(); + + // add all nodes that had no Key (using document order) + for (int i = 0; i < noKeyBucket.size(); i++) { + nodes->add(noKeyBucket.get(i)); + } + + // Add All nodes with sorted keys + for (int i = 0; i < nbrKeys; i++) { + + NodeSet* bucket = (NodeSet*) keyHash.remove(*keys[i]); + + //-- set keys[i] = 0 so that it doesn't get deleted twice + //-- since deleting "list" will delete the keys + keys[i] = 0; + + // Sort Buckets if necessary (Not Yet Implemented) + //if (bucket.size() > 1) { + // bucket = sort(bucket,newSortElements,context,pState); + //} + for (int j = 0; j < bucket->size(); j++) { + nodes->add(bucket->get(j)); + } + delete bucket; + } + + delete keys; + //-- important to delete after we set keys[0..n] = 0; + //-- since the list destructor will delete the String pointers + delete list; + +} //-- sort + + + +/** + * Sorts the given String[] +**/ +void NodeSorter::sortKeys + (String** keys, int length, MBool ascending, const String& dataType, const String& lang) +{ + + if (length < 2) return; + + StringComparator* comparator = StringComparator::getInstance(lang); + + String** sorted = new String*[length]; + + int nbrSorted = 0; + + while (nbrSorted < length) { + + int next = 0; + //-- advance to next key + while (!keys[next]) ++next; + + //-- find smallest + for (int i = next+1; i < length; i++) { + + if (!keys[i]) continue; + + if (ascending) { + if (comparator->compare(*keys[i], *keys[next]) < 0) next = i; + } + else { + if (comparator->compare(*keys[i], *keys[next]) > 0) next = i; + } + } + + sorted[nbrSorted++] = keys[next]; + keys[next] = 0; + } + + //-- swap + for (int i = 0; i < length; i++) { + keys[i] = sorted[i]; + sorted[i] = 0; + } + //-- clean + delete comparator; + delete [] sorted; + +} //-- sortKeys + +/** + * Sorts the given String Array by converting the Strings to Numbers + * and performing a comparison + * @return the new sorted String Array +** +private static String[] sortAsNumbers + (String[] strings, MBool ascending, String lang) +{ + if (strings.length == 0) return new String[0]; + + List sorted = new List(strings.length); + sorted.add(strings[0]); + String key; + int comp = -1; + // Uses a simple insertion sort + for (int i = 1; i < strings.length; i++) { + key = strings[i]; + for (int j = 0; j < sorted.size(); j++) { + comp = compareAsNumbers(key, (String)sorted.get(j)); + + // Ascending + if (ascending) { + if (comp < 0) { + sorted.add(j, key); + break; + } + else if (j == sorted.size()-1) { + sorted.add(key); + break; + } + } + // Descending + else { + if (comp > 0) { + sorted.add(j, key); + break; + } + else if (j == sorted.size()-1) { + sorted.add(key); + break; + } + } + } //-- end for each sorted key + } + return (String[]) sorted.toArray(new String[sorted.size()]); + + } //-- sortAsNumbers + + + private static int compareAsNumbers(String strA, String strB) { + double dblA, dblB; + + try { dblA = (Double.valueOf(strA)).doubleValue(); } + catch(NumberFormatException nfe) { dblA = 0; } + try { dblB = (Double.valueOf(strB)).doubleValue(); } + catch(NumberFormatException nfe) { dblB = 0; } + + if (dblA < dblB) return -1; + else if (dblA == dblB) return 0; + else return 1; + } //-- compareAsNumbers + +*/ diff --git a/mozilla/extensions/transformiix/source/xslt/util/NodeSorter.h b/mozilla/extensions/transformiix/source/xslt/util/NodeSorter.h new file mode 100644 index 00000000000..937822f185d --- /dev/null +++ b/mozilla/extensions/transformiix/source/xslt/util/NodeSorter.h @@ -0,0 +1,73 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is XSL:P XSLT processor. + * + * The Initial Developer of the Original Code is Keith Visco. + * Portions created by Keith Visco (C) 1999-2000 Keith Visco. + * All Rights Reserved.. + * + * Contributor(s): + * + * Keith Visco, kvisco@ziplink.net + * -- original author. + * + * $Id: NodeSorter.h,v 1.1 2000-04-12 10:55:55 kvisco%ziplink.net Exp $ + */ + + +#include "String.h" +#include "StringComparator.h" +#include "NamedMap.h" +#include "dom.h" +#include "NodeSet.h" +#include "ProcessorState.h" +#include "Names.h" +/* + * Sorts Nodes as specified by the W3C XSLT 1.0 Recommendation + */ + +#ifndef TRANSFRMX_NODESORTER_H +#define TRANSFRMX_NODESORTER_H + +class NodeSorter { + +public: + + //-- static variables + static const String DEFAULT_LANG; + static const String ASCENDING_ORDER; + static const String DESCENDING_ORDER; + static const String TEXT_TYPE; + static const String NUMBER_TYPE; + + /** + * Sorts the given Node Array using this XSLSort's properties as a + * basis for the sort + * @param nodes the Array of nodes to sort + * @param pState the ProcessorState to evaluate the Select pattern with + * @return the a new Array of sorted nodes + **/ + static void sort + (NodeSet* nodes, Element* sortElement, Node* context, ProcessorState* ps); + +private: + + /** + * Sorts the given String[] + **/ + static void sortKeys + (String** keys, int length, MBool ascending, const String& dataType, const String& lang); + + +}; + +#endif