зеркало из https://github.com/mozilla/pjs.git
initial checkin of NodeSorter.h/cpp which as the name suggests handles Node sorting
This commit is contained in:
Родитель
35479dca25
Коммит
1ae2c0fce6
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
*/
|
|
@ -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
|
Загрузка…
Ссылка в новой задаче