GME  13
DOMXPathExpressionImpl.cpp
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  *
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "DOMXPathExpressionImpl.hpp"
00019 #include "DOMXPathResultImpl.hpp"
00020 #include <xercesc/validators/schema/identity/XercesXPath.hpp>
00021 #include <xercesc/validators/schema/identity/XPathMatcher.hpp>
00022 #include <xercesc/validators/schema/identity/XPathException.hpp>
00023 #include <xercesc/validators/schema/SchemaElementDecl.hpp>
00024 #include <xercesc/util/StringPool.hpp>
00025 #include <xercesc/util/OutOfMemoryException.hpp>
00026 #include <xercesc/dom/DOMXPathException.hpp>
00027 #include <xercesc/dom/DOM.hpp>
00028 
00029 XERCES_CPP_NAMESPACE_BEGIN
00030 
00031 class WrapperForXPathNSResolver : public XercesNamespaceResolver
00032 {
00033 public:
00034     WrapperForXPathNSResolver(XMLStringPool* pool, const DOMXPathNSResolver *resolver, MemoryManager* const manager) :
00035       fStringPool(pool),
00036       fResolver(resolver),
00037       fMemoryManager(manager)
00038     {
00039     }
00040 
00041     virtual unsigned int getNamespaceForPrefix(const XMLCh* const prefix) const
00042     {
00043         if(fResolver==NULL)
00044             throw DOMException(DOMException::NAMESPACE_ERR, 0, fMemoryManager);
00045         const XMLCh* nsUri=fResolver->lookupNamespaceURI(prefix);
00046         if(nsUri==NULL)
00047             throw DOMException(DOMException::NAMESPACE_ERR, 0, fMemoryManager);
00048         return fStringPool->addOrFind(nsUri);
00049     }
00050 
00051 protected:
00052     XMLStringPool*              fStringPool;
00053     const DOMXPathNSResolver *  fResolver;
00054     MemoryManager* const        fMemoryManager;
00055 };
00056 
00057 
00058 typedef JanitorMemFunCall<DOMXPathExpressionImpl>     CleanupType;
00059 
00060 DOMXPathExpressionImpl::DOMXPathExpressionImpl(const XMLCh *expression, const DOMXPathNSResolver *resolver, MemoryManager* const manager) :
00061  fStringPool(NULL),
00062  fParsedExpression(NULL),
00063  fExpression(NULL),
00064  fMoveToRoot(false),
00065  fMemoryManager(manager)
00066 {
00067     if(expression==NULL || *expression==0)
00068         throw DOMXPathException(DOMXPathException::INVALID_EXPRESSION_ERR, 0, fMemoryManager);
00069 
00070     CleanupType cleanup(this, &DOMXPathExpressionImpl::cleanUp);
00071     fStringPool = new (fMemoryManager) XMLStringPool(109, fMemoryManager);
00072     // XercesPath will complain if the expression starts with '/', add a "." in front of it and start from the document root
00073     if(*expression==chForwardSlash)
00074     {
00075         fExpression=(XMLCh*)fMemoryManager->allocate((XMLString::stringLen(expression)+2)*sizeof(XMLCh));
00076         *fExpression = chPeriod;
00077         *(fExpression+1) = chNull;
00078         XMLString::catString(fExpression, expression);
00079         fMoveToRoot=true;
00080     }
00081     else
00082         fExpression=XMLString::replicate(expression);
00083 
00084     try
00085     {
00086         WrapperForXPathNSResolver wrappedResolver(fStringPool, resolver, fMemoryManager);
00087         fParsedExpression = new (fMemoryManager) XercesXPath(fExpression, fStringPool, &wrappedResolver, 0, true, fMemoryManager);
00088     }
00089     catch(const XPathException& )
00090     {
00091         throw DOMXPathException(DOMXPathException::INVALID_EXPRESSION_ERR, 0, fMemoryManager);
00092     }
00093     catch(const OutOfMemoryException&)
00094     {
00095         cleanup.release();
00096 
00097         throw;
00098     }
00099 
00100     cleanup.release();
00101 }
00102 
00103 DOMXPathExpressionImpl::~DOMXPathExpressionImpl()
00104 {
00105     cleanUp();
00106 }
00107 
00108 void DOMXPathExpressionImpl::cleanUp()
00109 {
00110     XMLString::release(&fExpression, fMemoryManager);
00111     delete fParsedExpression;
00112     delete fStringPool;
00113 }
00114 
00115 DOMXPathResult* DOMXPathExpressionImpl::evaluate(const DOMNode *contextNode,
00116                                                  DOMXPathResult::ResultType type,
00117                                                  DOMXPathResult* result) const
00118 {
00119     if(type!=DOMXPathResult::FIRST_ORDERED_NODE_TYPE && type!=DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE &&
00120        type!=DOMXPathResult::ANY_UNORDERED_NODE_TYPE && type!=DOMXPathResult::UNORDERED_NODE_SNAPSHOT_TYPE)
00121         throw DOMXPathException(DOMXPathException::TYPE_ERR, 0, fMemoryManager);
00122 
00123     if(contextNode==NULL || contextNode->getNodeType()!=DOMNode::ELEMENT_NODE)
00124         throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, fMemoryManager);
00125 
00126     JanitorMemFunCall<DOMXPathResultImpl> r_cleanup (
00127       0, &DOMXPathResultImpl::release);
00128     DOMXPathResultImpl* r=(DOMXPathResultImpl*)result;
00129     if(r==NULL)
00130     {
00131       r=new (fMemoryManager) DOMXPathResultImpl(type, fMemoryManager);
00132       r_cleanup.reset (r);
00133     }
00134     else
00135         r->reset(type);
00136 
00137     XPathMatcher matcher(fParsedExpression, fMemoryManager);
00138     matcher.startDocumentFragment();
00139 
00140     if(fMoveToRoot)
00141     {
00142         contextNode=contextNode->getOwnerDocument();
00143         if(contextNode==NULL)
00144             throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, fMemoryManager);
00145 
00146         QName qName(contextNode->getNodeName(), 0, fMemoryManager);
00147         SchemaElementDecl elemDecl(&qName);
00148         RefVectorOf<XMLAttr> attrList(0, true, fMemoryManager);
00149         matcher.startElement(elemDecl, 0, XMLUni::fgZeroLenString, attrList, 0);
00150         DOMNode* child=contextNode->getFirstChild();
00151         while(child)
00152         {
00153             if(child->getNodeType()==DOMNode::ELEMENT_NODE)
00154                 testNode(&matcher, r, (DOMElement*)child);
00155             child=child->getNextSibling();
00156         }
00157         matcher.endElement(elemDecl, XMLUni::fgZeroLenString);
00158     }
00159     else
00160         testNode(&matcher, r, (DOMElement*)contextNode);
00161 
00162     r_cleanup.release ();
00163     return r;
00164 }
00165 
00166 bool DOMXPathExpressionImpl::testNode(XPathMatcher* matcher, DOMXPathResultImpl* result, DOMElement *node) const
00167 {
00168     int uriId=fStringPool->addOrFind(node->getNamespaceURI());
00169     QName qName(node->getNodeName(), uriId, fMemoryManager);
00170     SchemaElementDecl elemDecl(&qName);
00171     DOMNamedNodeMap* attrMap=node->getAttributes();
00172     XMLSize_t attrCount = attrMap->getLength();
00173     RefVectorOf<XMLAttr> attrList(attrCount, true, fMemoryManager);
00174     for(XMLSize_t i=0;i<attrCount;i++)
00175     {
00176         DOMAttr* attr=(DOMAttr*)attrMap->item(i);
00177         attrList.addElement(new (fMemoryManager) XMLAttr(fStringPool->addOrFind(attr->getNamespaceURI()),
00178                                                          attr->getNodeName(),
00179                                                          attr->getNodeValue(),
00180                                                          XMLAttDef::CData,
00181                                                          attr->getSpecified(),
00182                                                          fMemoryManager,
00183                                                          NULL,
00184                                                          true));
00185     }
00186     matcher->startElement(elemDecl, uriId, node->getPrefix(), attrList, attrCount);
00187     unsigned char nMatch=matcher->isMatched();
00188     if(nMatch!=0 && nMatch!=XPathMatcher::XP_MATCHED_DP)
00189     {
00190         result->addResult(node);
00191         if(result->getResultType()==DOMXPathResult::ANY_UNORDERED_NODE_TYPE || result->getResultType()==DOMXPathResult::FIRST_ORDERED_NODE_TYPE)
00192             return true;    // abort navigation, we found one result
00193     }
00194 
00195     if(nMatch==0 || nMatch==XPathMatcher::XP_MATCHED_D || nMatch==XPathMatcher::XP_MATCHED_DP)
00196     {
00197         DOMNode* child=node->getFirstChild();
00198         while(child)
00199         {
00200             if(child->getNodeType()==DOMNode::ELEMENT_NODE)
00201                 if(testNode(matcher, result, (DOMElement*)child))
00202                     return true;
00203             child=child->getNextSibling();
00204         }
00205     }
00206     matcher->endElement(elemDecl, XMLUni::fgZeroLenString);
00207     return false;
00208 }
00209 
00210 void DOMXPathExpressionImpl::release()
00211 {
00212     DOMXPathExpressionImpl* me = this;
00213     delete me;
00214 }
00215 
00216 XERCES_CPP_NAMESPACE_END