Warning, file /frameworks/khtml/src/xpath/path.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * path.cc - Copyright 2005 Frerich Raabe <raabe@kde.org>
0003  *
0004  * Redistribution and use in source and binary forms, with or without
0005  * modification, are permitted provided that the following conditions
0006  * are met:
0007  *
0008  * 1. Redistributions of source code must retain the above copyright
0009  *    notice, this list of conditions and the following disclaimer.
0010  * 2. Redistributions in binary form must reproduce the above copyright
0011  *    notice, this list of conditions and the following disclaimer in the
0012  *    documentation and/or other materials provided with the distribution.
0013  *
0014  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0015  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0016  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0017  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0018  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0019  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0020  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0021  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0022  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0023  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0024  */
0025 #include "path.h"
0026 
0027 #include "xml/dom_docimpl.h"
0028 #include "xml/dom_nodeimpl.h"
0029 
0030 using namespace DOM;
0031 using namespace khtml;
0032 using namespace khtml::XPath;
0033 
0034 Filter::Filter(Expression *expr, const QList<Predicate *> &predicates)
0035     : m_expr(expr),
0036       m_predicates(predicates)
0037 {
0038 }
0039 
0040 Filter::~Filter()
0041 {
0042     delete m_expr;
0043     qDeleteAll(m_predicates);
0044 }
0045 
0046 QString Filter::dump() const
0047 {
0048     QString s = "<filter>";
0049     s += m_expr->dump();
0050     foreach (Predicate *predicate, m_predicates) {
0051         s += predicate->dump();
0052     }
0053     s += "</filter>";
0054     return s;
0055 }
0056 
0057 Value Filter::doEvaluate() const
0058 {
0059     Value v = m_expr->evaluate();
0060     if (!v.isNodeset()) {
0061         if (!m_predicates.empty()) {
0062             // qCDebug(KHTML_LOG) << "Ignoring predicates for filter since expression does not evaluate to a nodeset!";
0063         }
0064         return v;
0065     }
0066 
0067     DomNodeList inNodes = v.toNodeset(), outNodes;
0068 
0069     // Filter seems to work in document order, not axis order
0070     inNodes->normalizeUpto(StaticNodeListImpl::DocumentOrder);
0071 
0072     foreach (Predicate *predicate, m_predicates) {
0073         outNodes = new StaticNodeListImpl();
0074         Expression::evaluationContext().size = int(inNodes->length());
0075 
0076         for (unsigned long n = 0; n < inNodes->length(); ++n) {
0077             NodeImpl *node = inNodes->item(n);
0078             Expression::evaluationContext().node = node;
0079             Expression::evaluationContext().position = n + 1;
0080 
0081             if (predicate->evaluate()) {
0082                 outNodes->append(node);
0083             }
0084         }
0085 
0086         inNodes = outNodes;
0087         outNodes->setKnownNormalization(StaticNodeListImpl::DocumentOrder);
0088 
0089 #ifdef XPATH_VERBOSE
0090         qCDebug(KHTML_LOG) << "Predicate within filter trims to:" << outNodes->length();
0091 #endif
0092     }
0093 
0094     return Value(outNodes);
0095 }
0096 
0097 LocationPath::LocationPath()
0098     : m_absolute(false)
0099 {
0100 }
0101 
0102 LocationPath::~LocationPath()
0103 {
0104     qDeleteAll(m_steps);
0105 }
0106 
0107 void LocationPath::optimize()
0108 {
0109     foreach (Step *step, m_steps) {
0110         step->optimize();
0111     }
0112 }
0113 
0114 Value LocationPath::doEvaluate() const
0115 {
0116 #ifdef XPATH_VERBOSE
0117     if (m_absolute) {
0118         qCDebug(KHTML_LOG) << "Evaluating absolute path expression, steps:" << m_steps.count();
0119     } else {
0120         qCDebug(KHTML_LOG) << "Evaluating relative path expression, steps:" << m_steps.count();
0121     }
0122 #endif
0123 
0124     DomNodeList inDomNodes  = new StaticNodeListImpl,
0125     outDomNodes;
0126 
0127     /* For absolute location paths, the context node is ignored - the
0128      * document's root node is used instead.
0129      */
0130     NodeImpl *context = Expression::evaluationContext().node;
0131     if (m_absolute) {
0132         if (context->nodeType() != Node::DOCUMENT_NODE) {
0133             context = context->ownerDocument();
0134         }
0135     }
0136 
0137     inDomNodes->append(context);
0138 
0139     if (m_steps.isEmpty()) {
0140         return Value(inDomNodes);
0141     }
0142 
0143     int s = 0;
0144     foreach (Step *step, m_steps) {
0145 #ifdef XPATH_VERBOSE
0146         qCDebug(KHTML_LOG) << "-------------------------------------";
0147         qCDebug(KHTML_LOG) << "Step " << s << "insize " << inDomNodes->length();
0148 #endif
0149 
0150         outDomNodes = new StaticNodeListImpl;
0151         for (unsigned long i = 0; i < inDomNodes->length(); ++i) {
0152             DomNodeList matches = step->evaluate(inDomNodes->item(i));
0153             for (unsigned long j = 0; j < matches->length(); ++j) {
0154                 outDomNodes->append(matches->item(j));
0155             }
0156         }
0157         inDomNodes = outDomNodes;
0158 
0159         ++s;
0160     }
0161 
0162 #ifdef XPATH_VERBOSE
0163     qCDebug(KHTML_LOG) << "-------------------------------------";
0164     qCDebug(KHTML_LOG) << "output:" << outDomNodes->length();
0165     qCDebug(KHTML_LOG) << "=====================================";
0166 #endif
0167 
0168     return Value(outDomNodes);
0169 }
0170 
0171 QString LocationPath::dump() const
0172 {
0173     QString s = "<locationpath absolute=\"";
0174     s += m_absolute ? "true" : "false";
0175     s += "\">";
0176     foreach (Step *step, m_steps) {
0177         s += step->dump();
0178     }
0179     s += "</locationpath>";
0180     return s;
0181 }
0182 
0183 Path::Path(Filter *filter, LocationPath *path)
0184     : m_filter(filter),
0185       m_path(path)
0186 {
0187 }
0188 
0189 Path::~Path()
0190 {
0191     delete m_filter;
0192     delete m_path;
0193 }
0194 
0195 QString Path::dump() const
0196 {
0197     if (!m_filter && !m_path) {
0198         return "<path/>";
0199     }
0200 
0201     QString s = "<path>";
0202     if (m_filter) {
0203         s += m_filter->dump();
0204     }
0205     if (m_path) {
0206         s += m_path->dump();
0207     }
0208     s += "</path>";
0209 
0210     return s;
0211 }
0212 
0213 Value Path::doEvaluate() const
0214 {
0215     NodeImpl *saveCtx = Expression::evaluationContext().node;
0216 
0217     Value initial =  m_filter->evaluate();
0218     if (initial.isNodeset()) {
0219         // Pass in every output from the filter to the path, and union the results
0220         DomNodeList out = new StaticNodeListImpl();
0221         DomNodeList in  = initial.toNodeset();
0222 
0223         for (unsigned long i = 0; i < in->length(); ++i) {
0224             Expression::evaluationContext().node = in->item(i);
0225 
0226             DomNodeList singleSet = m_path->evaluate().toNodeset();
0227             for (unsigned long j = 0; j < singleSet->length(); ++ j) {
0228                 out->append(singleSet->item(j));
0229             }
0230         }
0231 
0232         Expression::evaluationContext().node = saveCtx;
0233         return Value(out);
0234     } else {
0235         // ### what should happen in this case?
0236         Expression::reportInvalidExpressionErr();
0237         return Value();
0238     }
0239 }
0240