KHTML
path.cpp
Go to the documentation of this file.
00001 /* 00002 * path.cc - Copyright 2005 Frerich Raabe <raabe@kde.org> 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions 00006 * are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 00014 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00015 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00016 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00017 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 00018 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 00019 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00020 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00021 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00022 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 00023 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00024 */ 00025 #include "path.h" 00026 00027 #include "xml/dom_docimpl.h" 00028 #include "xml/dom_nodeimpl.h" 00029 00030 using namespace DOM; 00031 using namespace khtml; 00032 using namespace khtml::XPath; 00033 00034 Filter::Filter( Expression *expr, const QList<Predicate *> &predicates ) 00035 : m_expr( expr ), 00036 m_predicates( predicates ) 00037 { 00038 } 00039 00040 Filter::~Filter() 00041 { 00042 delete m_expr; 00043 qDeleteAll( m_predicates ); 00044 } 00045 00046 QString Filter::dump() const 00047 { 00048 QString s = "<filter>"; 00049 s += m_expr->dump(); 00050 foreach( Predicate *predicate, m_predicates ) { 00051 s += predicate->dump(); 00052 } 00053 s += "</filter>"; 00054 return s; 00055 } 00056 00057 Value Filter::doEvaluate() const 00058 { 00059 Value v = m_expr->evaluate(); 00060 if ( !v.isNodeset() ) { 00061 if ( !m_predicates.empty() ) { 00062 kDebug(6011) << "Ignoring predicates for filter since expression does not evaluate to a nodeset!"; 00063 } 00064 return v; 00065 } 00066 00067 DomNodeList inNodes = v.toNodeset(), outNodes; 00068 00069 // Filter seems to work in document order, not axis order 00070 inNodes->normalizeUpto(StaticNodeListImpl::DocumentOrder); 00071 00072 foreach( Predicate *predicate, m_predicates ) { 00073 outNodes = new StaticNodeListImpl(); 00074 Expression::evaluationContext().size = int(inNodes->length()); 00075 00076 for ( unsigned long n = 0; n < inNodes->length(); ++n ) { 00077 NodeImpl *node = inNodes->item(n); 00078 Expression::evaluationContext().node = node; 00079 Expression::evaluationContext().position = n + 1; 00080 00081 if ( predicate->evaluate() ) { 00082 outNodes->append( node ); 00083 } 00084 } 00085 00086 inNodes = outNodes; 00087 outNodes->setKnownNormalization(StaticNodeListImpl::DocumentOrder); 00088 00089 #ifdef XPATH_VERBOSE 00090 kDebug(6011) << "Predicate within filter trims to:" << outNodes->length(); 00091 #endif 00092 } 00093 00094 return Value( outNodes ); 00095 } 00096 00097 LocationPath::LocationPath() 00098 : m_absolute( false ) 00099 { 00100 } 00101 00102 LocationPath::~LocationPath() 00103 { 00104 qDeleteAll( m_steps ); 00105 } 00106 00107 void LocationPath::optimize() 00108 { 00109 foreach( Step *step, m_steps ) { 00110 step->optimize(); 00111 } 00112 } 00113 00114 Value LocationPath::doEvaluate() const 00115 { 00116 #ifdef XPATH_VERBOSE 00117 if ( m_absolute ) { 00118 kDebug(6011) << "Evaluating absolute path expression, steps:" << m_steps.count(); 00119 } else { 00120 kDebug(6011) << "Evaluating relative path expression, steps:" << m_steps.count(); 00121 } 00122 #endif 00123 00124 DomNodeList inDomNodes = new StaticNodeListImpl, 00125 outDomNodes; 00126 00127 /* For absolute location paths, the context node is ignored - the 00128 * document's root node is used instead. 00129 */ 00130 NodeImpl *context = Expression::evaluationContext().node; 00131 if ( m_absolute ) { 00132 if ( context->nodeType() != Node::DOCUMENT_NODE ) { 00133 context = context->ownerDocument(); 00134 } 00135 } 00136 00137 inDomNodes->append( context ); 00138 00139 if ( m_steps.isEmpty() ) 00140 return Value( inDomNodes ); 00141 00142 int s = 0; 00143 foreach( Step *step, m_steps ) { 00144 #ifdef XPATH_VERBOSE 00145 kDebug(6011) << "-------------------------------------"; 00146 kDebug(6011) << "Step " << s << "insize " << inDomNodes->length(); 00147 #endif 00148 00149 outDomNodes = new StaticNodeListImpl; 00150 for ( unsigned long i = 0; i < inDomNodes->length(); ++i ) { 00151 DomNodeList matches = step->evaluate( inDomNodes->item( i ) ); 00152 for ( unsigned long j = 0; j < matches->length(); ++j ) 00153 outDomNodes->append( matches->item( j ) ); 00154 } 00155 inDomNodes = outDomNodes; 00156 00157 ++s; 00158 } 00159 00160 #ifdef XPATH_VERBOSE 00161 kDebug(6011) << "-------------------------------------"; 00162 kDebug(6011) << "output:" <<outDomNodes->length(); 00163 kDebug(6011) << "====================================="; 00164 #endif 00165 00166 return Value( outDomNodes ); 00167 } 00168 00169 QString LocationPath::dump() const 00170 { 00171 QString s = "<locationpath absolute=\""; 00172 s += m_absolute ? "true" : "false"; 00173 s += "\">"; 00174 foreach( Step *step, m_steps ) { 00175 s += step->dump(); 00176 } 00177 s += "</locationpath>"; 00178 return s; 00179 } 00180 00181 Path::Path( Filter *filter, LocationPath *path ) 00182 : m_filter( filter ), 00183 m_path( path ) 00184 { 00185 } 00186 00187 Path::~Path() 00188 { 00189 delete m_filter; 00190 delete m_path; 00191 } 00192 00193 QString Path::dump() const 00194 { 00195 if ( !m_filter && !m_path ) { 00196 return "<path/>"; 00197 } 00198 00199 QString s = "<path>"; 00200 if ( m_filter ) { 00201 s += m_filter->dump(); 00202 } 00203 if ( m_path ) { 00204 s += m_path->dump(); 00205 } 00206 s += "</path>"; 00207 00208 return s; 00209 } 00210 00211 Value Path::doEvaluate() const 00212 { 00213 NodeImpl* saveCtx = Expression::evaluationContext().node; 00214 00215 Value initial = m_filter->evaluate(); 00216 if ( initial.isNodeset() ) { 00217 // Pass in every output from the filter to the path, and union the results 00218 DomNodeList out = new StaticNodeListImpl(); 00219 DomNodeList in = initial.toNodeset(); 00220 00221 for (unsigned long i = 0; i < in->length(); ++i) { 00222 Expression::evaluationContext().node = in->item(i); 00223 00224 DomNodeList singleSet = m_path->evaluate().toNodeset(); 00225 for (unsigned long j = 0; j < singleSet->length(); ++ j) 00226 out->append(singleSet->item(j)); 00227 } 00228 00229 Expression::evaluationContext().node = saveCtx; 00230 return Value(out); 00231 } else { 00232 // ### what should happen in this case? 00233 Expression::reportInvalidExpressionErr(); 00234 return Value(); 00235 } 00236 } 00237 00238 // kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
KDE 4.6 API Reference