source: icXML/icXML-devel/src/icxercesc/dom/impl/DOMXPathExpressionImpl.cpp @ 2774

Last change on this file since 2774 was 2774, checked in by cameron, 6 years ago

Various fixes

File size: 8.3 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include "DOMXPathExpressionImpl.hpp"
19#include "DOMXPathResultImpl.hpp"
20#include <xercesc/validators/schema/identity/XercesXPath.hpp>
21#include <xercesc/validators/schema/identity/XPathMatcher.hpp>
22#include <xercesc/validators/schema/identity/XPathException.hpp>
23#include <xercesc/validators/schema/SchemaElementDecl.hpp>
24#include <xercesc/util/StringPool.hpp>
25#include <xercesc/util/OutOfMemoryException.hpp>
26#include <xercesc/dom/DOMXPathException.hpp>
27#include <xercesc/dom/DOM.hpp>
28
29XERCES_CPP_NAMESPACE_BEGIN
30
31class WrapperForXPathNSResolver : public XercesNamespaceResolver
32{
33public:
34    WrapperForXPathNSResolver(XMLStringPool* pool, const DOMXPathNSResolver *resolver, MemoryManager* const manager) :
35      fStringPool(pool),
36      fResolver(resolver),
37      fMemoryManager(manager)
38    {
39    }
40
41    virtual unsigned int getNamespaceForPrefix(const XMLCh* const prefix) const
42    {
43        if(fResolver==NULL)
44            throw DOMException(DOMException::NAMESPACE_ERR, 0, fMemoryManager);
45        const XMLCh* nsUri=fResolver->lookupNamespaceURI(prefix);
46        if(nsUri==NULL)
47            throw DOMException(DOMException::NAMESPACE_ERR, 0, fMemoryManager);
48        return fStringPool->addOrFind(nsUri);
49    }
50
51protected:
52    XMLStringPool*              fStringPool;
53    const DOMXPathNSResolver *  fResolver;
54    MemoryManager* const        fMemoryManager;
55};
56
57
58typedef JanitorMemFunCall<DOMXPathExpressionImpl>     CleanupType;
59
60DOMXPathExpressionImpl::DOMXPathExpressionImpl(const XMLCh *expression, const DOMXPathNSResolver *resolver, MemoryManager* const manager) :
61 fStringPool(NULL),
62 fParsedExpression(NULL),
63 fExpression(NULL),
64 fMoveToRoot(false),
65 fMemoryManager(manager)
66{
67    if(expression==NULL || *expression==0)
68        throw DOMXPathException(DOMXPathException::INVALID_EXPRESSION_ERR, 0, fMemoryManager);
69
70    CleanupType cleanup(this, &DOMXPathExpressionImpl::cleanUp);
71    fStringPool = new (fMemoryManager) XMLStringPool(109, fMemoryManager);
72    // XercesPath will complain if the expression starts with '/', add a "." in front of it and start from the document root
73    if(*expression==chForwardSlash)
74    {
75        fExpression=(XMLCh*)fMemoryManager->allocate((XMLString::stringLen(expression)+2)*sizeof(XMLCh));
76        *fExpression = chPeriod;
77        *(fExpression+1) = chNull;
78        XMLString::catString(fExpression, expression);
79        fMoveToRoot=true;
80    }
81    else
82        fExpression=XMLString::replicate(expression);
83
84    try
85    {
86        WrapperForXPathNSResolver wrappedResolver(fStringPool, resolver, fMemoryManager);
87        fParsedExpression = new (fMemoryManager) XercesXPath(fExpression, fStringPool, &wrappedResolver, 0, true, fMemoryManager);
88    }
89    catch(const XPathException& )
90    {
91        throw DOMXPathException(DOMXPathException::INVALID_EXPRESSION_ERR, 0, fMemoryManager);
92    }
93    catch(const OutOfMemoryException&)
94    {
95        cleanup.release();
96
97        throw;
98    }
99
100    cleanup.release();
101}
102
103DOMXPathExpressionImpl::~DOMXPathExpressionImpl()
104{
105    cleanUp();
106}
107
108void DOMXPathExpressionImpl::cleanUp()
109{
110    XMLString::release(&fExpression, fMemoryManager);
111    delete fParsedExpression;
112    delete fStringPool;
113}
114
115DOMXPathResult* DOMXPathExpressionImpl::evaluate(const DOMNode *contextNode,
116                                                 DOMXPathResult::ResultType type,
117                                                 DOMXPathResult* result) const
118{
119    if(type!=DOMXPathResult::FIRST_ORDERED_NODE_TYPE && type!=DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE &&
120       type!=DOMXPathResult::ANY_UNORDERED_NODE_TYPE && type!=DOMXPathResult::UNORDERED_NODE_SNAPSHOT_TYPE)
121        throw DOMXPathException(DOMXPathException::TYPE_ERR, 0, fMemoryManager);
122
123    if(contextNode==NULL || contextNode->getNodeType()!=DOMNode::ELEMENT_NODE)
124        throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, fMemoryManager);
125
126    JanitorMemFunCall<DOMXPathResultImpl> r_cleanup (
127      0, &DOMXPathResultImpl::release);
128    DOMXPathResultImpl* r=(DOMXPathResultImpl*)result;
129    if(r==NULL)
130    {
131      r=new (fMemoryManager) DOMXPathResultImpl(type, fMemoryManager);
132      r_cleanup.reset (r);
133    }
134    else
135        r->reset(type);
136
137    XPathMatcher matcher(fParsedExpression, fMemoryManager);
138    matcher.startDocumentFragment();
139
140    if(fMoveToRoot)
141    {
142        contextNode=contextNode->getOwnerDocument();
143        if(contextNode==NULL)
144            throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, fMemoryManager);
145
146        QName qName(contextNode->getNodeName(), 0, fMemoryManager);
147        SchemaElementDecl elemDecl(&qName);
148        RefVectorOf<XMLAttr> attrList(0, true, fMemoryManager);
149        matcher.startElement(elemDecl, 0, XMLUni::fgZeroLenString, attrList, 0);
150        DOMNode* child=contextNode->getFirstChild();
151        while(child)
152        {
153            if(child->getNodeType()==DOMNode::ELEMENT_NODE)
154                testNode(&matcher, r, (DOMElement*)child);
155            child=child->getNextSibling();
156        }
157        matcher.endElement(elemDecl, XMLUni::fgZeroLenString);
158    }
159    else
160        testNode(&matcher, r, (DOMElement*)contextNode);
161
162    r_cleanup.release ();
163    return r;
164}
165
166bool DOMXPathExpressionImpl::testNode(XPathMatcher* matcher, DOMXPathResultImpl* result, DOMElement *node) const
167{
168    int uriId=fStringPool->addOrFind(node->getNamespaceURI());
169    QName qName(node->getNodeName(), uriId, fMemoryManager);
170    SchemaElementDecl elemDecl(&qName);
171    DOMNamedNodeMap* attrMap=node->getAttributes();
172    XMLSize_t attrCount = attrMap->getLength();
173    RefVectorOf<XMLAttr> attrList(attrCount, true, fMemoryManager);
174    for(XMLSize_t i=0;i<attrCount;i++)
175    {
176        DOMAttr* attr=(DOMAttr*)attrMap->item(i);
177
178        unsigned int attrUriId = fStringPool->addOrFind(attr->getNamespaceURI());
179
180        QName * attrName = new (fMemoryManager) QName(attr->getNodeName(), attrUriId, fMemoryManager);
181
182        XMLAttr * xmlAttr = new (fMemoryManager) XMLAttr(attrName,
183                                                         attr->getNodeValue(),
184                                                         XMLAttDef::CData,
185                                                         attr->getSpecified(),
186                                                         fMemoryManager,
187                                                         NULL,
188                                                         true);
189
190        attrList.addElement(xmlAttr);
191    }
192    matcher->startElement(elemDecl, uriId, node->getPrefix(), attrList, attrCount);
193    unsigned char nMatch=matcher->isMatched();
194    if (nMatch!=0 && nMatch!=XPathMatcher::XP_MATCHED_DP)
195    {
196        result->addResult(node);
197        if (result->getResultType()==DOMXPathResult::ANY_UNORDERED_NODE_TYPE || result->getResultType()==DOMXPathResult::FIRST_ORDERED_NODE_TYPE)
198            return true;    // abort navigation, we found one result
199    }
200
201    if (nMatch==0 || nMatch==XPathMatcher::XP_MATCHED_D || nMatch==XPathMatcher::XP_MATCHED_DP)
202    {
203        DOMNode* child=node->getFirstChild();
204        while(child)
205        {
206            if(child->getNodeType()==DOMNode::ELEMENT_NODE)
207                if(testNode(matcher, result, (DOMElement*)child))
208                    return true;
209            child=child->getNextSibling();
210        }
211    }
212    matcher->endElement(elemDecl, XMLUni::fgZeroLenString);
213
214    for (XMLSize_t i = 0; i < attrCount; i++)
215    {
216        XMLAttr * attr = attrList.elementAt(i);
217        delete attr->fAttName;
218    }
219
220    return false;
221}
222
223void DOMXPathExpressionImpl::release()
224{
225    DOMXPathExpressionImpl* me = this;
226    delete me;
227}
228
229XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.