source: icXML/icXML-devel/src/icxercesc/validators/schema/XSDDOMParser.cpp @ 2774

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

Various fixes

File size: 16.1 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/**
19  * $Id: XSDDOMParser.cpp 729944 2008-12-29 17:03:32Z amassari $
20  */
21
22
23
24// ---------------------------------------------------------------------------
25//  Includes
26// ---------------------------------------------------------------------------
27#include <icxercesc/validators/schema/XSDDOMParser.hpp>
28#include <icxercesc/validators/schema/SchemaSymbols.hpp>
29#include <icxercesc/internal/XMLScanner.hpp>
30#include <icxercesc/internal/ElemStack.hpp>
31#include <xercesc/dom/DOMDocument.hpp>
32#include <xercesc/dom/impl/DOMElementImpl.hpp>
33#include <xercesc/dom/impl/DOMAttrImpl.hpp>
34#include <xercesc/dom/impl/DOMTextImpl.hpp>
35#include <xercesc/framework/XMLValidityCodes.hpp>
36#include <icxmlc/XMLNamespaceResolver.hpp>
37
38XERCES_CPP_NAMESPACE_BEGIN
39
40// static XMLSize_t docCharactersCount = 0;
41
42// ---------------------------------------------------------------------------
43//  XSDDOMParser: Constructors and Destructor
44// ---------------------------------------------------------------------------
45XSDDOMParser::XSDDOMParser( XMLValidator* const   valToAdopt
46                                                  , MemoryManager* const  manager
47                                                  , XMLGrammarPool* const gramPool):
48        XercesDOMParser(valToAdopt, manager, gramPool)
49        , fSawFatal(false)
50        , fAnnotationDepth(-1)
51        , fInnerAnnotationDepth(-1)
52        , fDepth(-1)
53        , fUserErrorReporter(0)
54        , fUserEntityHandler(0)
55        , fAnnotationBuf(1023, manager)
56    , fURIs(16, fMemoryManager)
57{
58        fXSDErrorReporter.setErrorReporter(this);
59        setValidationScheme(XercesDOMParser::Val_Never);
60        setDoNamespaces(true);
61}
62
63
64XSDDOMParser::~XSDDOMParser()
65{
66}
67
68
69// ---------------------------------------------------------------------------
70//  XSDDOMParser: Helper methods
71// ---------------------------------------------------------------------------
72DOMElement* XSDDOMParser::createElementNSNode(const XMLCh *namespaceURI,
73                                                                                          const XMLCh *qualifiedName)
74{
75        ReaderMgr::LastExtEntityInfo lastInfo;
76        ((ReaderMgr*) fScanner->getLocator())->getLastExtEntityInfo(lastInfo);
77
78        return getDocument()->createElementNS
79        (
80                namespaceURI
81                , qualifiedName
82                , lastInfo.lineNumber
83                , lastInfo.colNumber
84        );
85}
86
87
88void XSDDOMParser::startAnnotation( const XMLElementDecl&       elemDecl
89                                                                  , const RefVectorOf<XMLAttr>& attrList
90                                                                  , const XMLSize_t             attrCount)
91{
92        fAnnotationBuf.append(chOpenAngle);
93        fAnnotationBuf.append(elemDecl.getFullName());
94        fAnnotationBuf.append(chSpace);
95
96    // attributes are a bit of a pain.  To get this right, we have to keep track
97    // of the namespaces we've seen declared, then examine the namespace context
98    // for other namespaces so that we can also include them.
99    // optimized for simplicity and the case that not many
100    // namespaces are declared on this annotation...
101    fURIs.removeAllElements();
102
103        for (XMLSize_t i=0; i < attrCount; i++)
104        {
105                const XMLAttr* attribute = attrList.elementAt(i);
106
107        // if this attribute happens to be an xmlns attribute, we don't want to duplicate it in the annotation.
108        if (unlikely(attribute->isXMLNS()))
109        {
110            fURIs.addElement(fScanner->getUriResolver()->resolveUriId(attribute->getValue()));
111        }
112
113                fAnnotationBuf.append(attribute->getQName());
114                fAnnotationBuf.append(chEqual);
115                fAnnotationBuf.append(chDoubleQuote);
116        fAnnotationBuf.append(attribute->getValue());
117                fAnnotationBuf.append(chDoubleQuote);
118                fAnnotationBuf.append(chSpace);
119        }
120
121    // now we have to look through currently in-scope namespaces to see what
122    // wasn't declared here
123    BindingSetIterator namespaceContext = fScanner->getNamespaceIterator();
124    while (namespaceContext.next())
125    {
126        const unsigned int namespaceId = namespaceContext.pos();
127        const unsigned int uriId = fScanner->getNamespaceURIId(namespaceId);
128
129        if (unlikely(!fURIs.containsElement(uriId)))
130        {
131            fURIs.addElement(uriId);
132
133            const XMLCh* prefix = fScanner->getPrefixForNamespaceId(namespaceId);
134            if (*prefix == 0)
135            {
136                fAnnotationBuf.append(XMLUni::fgXMLNSString);
137            }
138            else
139            {
140                fAnnotationBuf.append(XMLUni::fgXMLNSColonString);
141                fAnnotationBuf.append(prefix);
142            }
143
144            fAnnotationBuf.append(chEqual);
145            fAnnotationBuf.append(chDoubleQuote);
146            fAnnotationBuf.append(fScanner->getURIText(uriId));
147            fAnnotationBuf.append(chDoubleQuote);
148            fAnnotationBuf.append(chSpace);
149        }
150    }
151
152    fAnnotationBuf.append(chCloseAngle);
153        fAnnotationBuf.append(chLF);
154}
155
156void XSDDOMParser::startAnnotationElement( const XMLElementDecl&       elemDecl
157                                                                                 , const RefVectorOf<XMLAttr>& attrList
158                                                                                 , const XMLSize_t             attrCount)
159{
160        fAnnotationBuf.append(chOpenAngle);
161        fAnnotationBuf.append(elemDecl.getFullName());
162
163        for(XMLSize_t i=0; i < attrCount; i++)
164        {
165                const XMLAttr* oneAttr = attrList.elementAt(i);
166                fAnnotationBuf.append(chSpace);
167                fAnnotationBuf.append(oneAttr->getQName());
168                fAnnotationBuf.append(chEqual);
169                fAnnotationBuf.append(chDoubleQuote);
170                fAnnotationBuf.append(oneAttr->getValue());
171                fAnnotationBuf.append(chDoubleQuote);
172        }
173
174        fAnnotationBuf.append(chCloseAngle);
175}
176
177void XSDDOMParser::endAnnotationElement( const XMLElementDecl& elemDecl
178                                                                           , bool complete)
179{
180        if (complete)
181        {
182                fAnnotationBuf.append(chLF);
183                fAnnotationBuf.append(chOpenAngle);
184                fAnnotationBuf.append(chForwardSlash);
185                fAnnotationBuf.append(elemDecl.getFullName());
186                fAnnotationBuf.append(chCloseAngle);
187
188                // note that this is always called after endElement on <annotation>'s
189                // child and before endElement on annotation.
190                // hence, we must make this the child of the current
191                // parent's only child.
192                DOMTextImpl *node = (DOMTextImpl *)fDocument->createTextNode(fAnnotationBuf.getRawBuffer());
193                fCurrentNode->appendChild(node);
194                fAnnotationBuf.reset();
195        }
196        else      //capturing character calls
197        {
198                fAnnotationBuf.append(chOpenAngle);
199                fAnnotationBuf.append(chForwardSlash);
200                fAnnotationBuf.append(elemDecl.getFullName());
201                fAnnotationBuf.append(chCloseAngle);
202        }
203}
204
205
206// ---------------------------------------------------------------------------
207//  XSDDOMParser: Setter methods
208// ---------------------------------------------------------------------------
209void XSDDOMParser::setUserErrorReporter(XMLErrorReporter* const errorReporter)
210{
211        fUserErrorReporter = errorReporter;
212        fScanner->setErrorReporter(this);
213}
214
215void XSDDOMParser::setUserEntityHandler(XMLEntityHandler* const entityHandler)
216{
217        fUserEntityHandler = entityHandler;
218        fScanner->setEntityHandler(this);
219}
220
221
222// ---------------------------------------------------------------------------
223//  XSDDOMParser: Implementation of the XMLDocumentHandler interface
224// ---------------------------------------------------------------------------
225void XSDDOMParser::startElement( const XMLElementDecl&       elemDecl
226                                                           , const unsigned int          urlId
227                                                           , const XMLCh* const          elemPrefix
228                                                           , const RefVectorOf<XMLAttr>& attrList
229                                                           , const XMLSize_t             attrCount
230                                                           , const bool                  isEmpty
231                                                           , const bool                  isRoot)
232{
233        fDepth++;
234
235        // while it is true that non-whitespace character data
236        // may only occur in appInfo or documentation
237        // elements, it's certainly legal for comments and PI's to
238        // occur as children of annotation; we need
239        // to account for these here.
240        if (fAnnotationDepth == -1)
241        {
242                if (XMLString::equals(elemDecl.getBaseName(), SchemaSymbols::fgELT_ANNOTATION) &&
243                        XMLString::equals(getURIText(urlId), SchemaSymbols::fgURI_SCHEMAFORSCHEMA))
244                {
245                        startAnnotation(elemDecl, attrList, attrCount);
246                        fAnnotationDepth = fDepth;
247                }
248        }
249        else
250        {
251                startAnnotationElement(elemDecl, attrList, attrCount);
252                if (fDepth == fAnnotationDepth + 1)
253                {
254                        fInnerAnnotationDepth = fDepth;
255                }
256                else
257                {
258                        if (isEmpty)
259                                endElement(elemDecl, urlId, isRoot, elemPrefix);
260                        return;
261                }
262        }
263
264
265
266        DOMElement *elem;
267
268        XMLNamespaceResolver* const fUriResolver = fScanner->getUriResolver();
269
270        if (urlId != XMLNamespaceResolver::fEmptyUriId)  //TagName has a prefix
271        {
272                const XMLCh * url = fUriResolver->getUriForId(urlId);
273
274                if (likely(elemPrefix && *elemPrefix))
275                {
276                        XMLBufBid elemQName(&fBufMgr);
277                        elemQName.set(elemPrefix);
278                        elemQName.append(chColon);
279                        elemQName.append(elemDecl.getBaseName());
280                        elem = createElementNSNode
281                        (
282                                url, elemQName.getRawBuffer()
283                        );
284                }
285                else
286                {
287                        elem = createElementNSNode
288                        (
289                                url, elemDecl.getBaseName()
290                        );
291                }
292        }
293        else
294        {
295                elem = createElementNSNode(NULL, elemDecl.getBaseName());
296        }
297
298        DOMElementImpl *elemImpl = (DOMElementImpl *) elem;
299        for (XMLSize_t index = 0; index < attrCount; ++index)
300        {
301                const XMLAttr* attribute = attrList.elementAt(index);
302
303                unsigned int attrURIId = attribute->getURIId();
304                const XMLCh* namespaceURI = NULL;
305
306                //for xmlns=...
307                if (XMLString::equals(attribute->getName(), XMLUni::fgXMLNSString))
308                {
309                        attrURIId = XMLNamespaceResolver::fXMLNSUriId;
310                        namespaceURI = (*fUriResolver)[XMLNamespaceResolver::fXMLNSUriId];
311                }
312                //TagName has a prefix
313                else if (attrURIId != XMLNamespaceResolver::fEmptyUriId)
314                {
315                        namespaceURI = fUriResolver->getUriForId(attrURIId, 1); //get namespaceURI
316                }
317
318
319                //  revisit.  Optimize to init the named node map to the
320                //            right size up front.
321                DOMAttrImpl *attr = (DOMAttrImpl *)
322                        fDocument->createAttributeNS(namespaceURI, attribute->getQName());
323
324                attr->setValue(attribute->getValue());
325                DOMNode* remAttr = elemImpl->setAttributeNodeNS(attr);
326                if (remAttr)
327                        remAttr->release();
328
329                // Attributes of type ID.  If this is one, add it to the hashtable of IDs
330                //   that is constructed for use by GetElementByID().
331                if (attribute->getType() == XMLAttDef::ID)
332                {
333                        if (fDocument->fNodeIDMap == 0)
334                                fDocument->fNodeIDMap = new (fDocument) DOMNodeIDMap(500, fDocument);
335                        fDocument->fNodeIDMap->add(attr);
336                        attr->fNode.isIdAttr(true);
337                }
338
339                attr->setSpecified(attribute->getSpecified());
340        }
341
342        // set up the default attributes
343        if (elemDecl.hasAttDefs())
344        {
345                XMLAttDefList* defAttrs = &elemDecl.getAttDefList();
346                XMLAttDef* attr = 0;
347                DOMAttrImpl * insertAttr = 0;
348
349                for (XMLSize_t i = 0; i < defAttrs->getAttDefCount(); i++)
350                {
351                        attr = &defAttrs->getAttDef(i);
352
353                        const XMLAttDef::DefAttTypes defType = attr->getDefaultType();
354                        if ((defType == XMLAttDef::Default) || (defType == XMLAttDef::Fixed))
355                        {
356                                // DOM Level 2 wants all namespace declaration attributes
357                                // to be bound to "http://www.w3.org/2000/xmlns/"
358                                // So as long as the XML parser doesn't do it, it needs to
359                                // done here.
360                                const XMLCh* qualifiedName = attr->getFullName();
361                                const XMLCh* namespaceURI = 0;
362
363                                unsigned int uriId =
364                                        fUriResolver->resolveUriId(attr->getAttName());
365
366                                if (XMLString::equals(qualifiedName, XMLUni::fgXMLNSString))
367                                        uriId = XMLNamespaceResolver::fXMLNSUriId;
368
369                                //TagName has a prefix
370                                if (uriId != XMLNamespaceResolver::fEmptyUriId)
371                                        namespaceURI = fUriResolver->getUriForId(uriId); //get namespaceURI
372
373                                insertAttr = (DOMAttrImpl *) fDocument->createAttributeNS
374                                (
375                                        namespaceURI
376                                        , qualifiedName
377                                );
378
379                                DOMAttr* remAttr = elemImpl->setDefaultAttributeNodeNS(insertAttr);
380                                if (remAttr)
381                                        remAttr->release();
382
383                                if (attr->getValue())
384                                {
385                                        insertAttr->setValue(attr->getValue());
386                                        insertAttr->setSpecified(false);
387                                }
388                        }
389
390                        insertAttr = 0;
391                        attr->reset();
392                }
393        }
394
395        fCurrentParent->appendChild(elem);
396        fCurrentParent = elem;
397        fCurrentNode = elem;
398        fWithinElement = true;
399
400        // If an empty element, do end right now (no endElement() will be called)
401        if (isEmpty)
402        {
403                endElement(elemDecl, urlId, isRoot, elemPrefix);
404        }
405}
406
407
408
409void XSDDOMParser::endElement( const XMLElementDecl & elemDecl
410                                                         , const unsigned int
411                                                         , const bool
412                                                         , const XMLCh* const)
413{
414        if (fAnnotationDepth > -1)
415        {
416                if (fInnerAnnotationDepth == fDepth)
417                {
418                        fInnerAnnotationDepth = -1;
419                        endAnnotationElement(elemDecl, false);
420                }
421                else if (fAnnotationDepth == fDepth)
422                {
423                        fAnnotationDepth = -1;
424                        endAnnotationElement(elemDecl, true);
425                }
426                else
427                {   // inside a child of annotation
428                        endAnnotationElement(elemDecl, false);
429                        fDepth--;
430                        return;
431                }
432        }
433
434        fDepth--;
435        fCurrentNode   = fCurrentParent;
436        fCurrentParent = fCurrentNode->getParentNode ();
437
438        // If we've hit the end of content, clear the flag.
439        //
440        if (fCurrentParent == fDocument)
441                fWithinElement = false;
442}
443
444void XSDDOMParser::docCharacters( const XMLCh*    const chars
445                                                                , const XMLSize_t       length
446                                                                , const bool            cdataSection)
447{
448        // Ignore chars outside of content
449        if (!fWithinElement)
450                return;
451
452        if (fInnerAnnotationDepth == -1)
453        {
454                if (!XMLString::isAllSpaces(chars, length))
455                {
456                        ReaderMgr::LastExtEntityInfo lastInfo;
457
458                        fScanner->getReaderMgr()->getLastExtEntityInfo(lastInfo);
459
460                        fXSLocator.setValues
461                        (   lastInfo.systemId
462                                , lastInfo.publicId
463                                , lastInfo.lineNumber
464                                , lastInfo.colNumber
465                        );
466                        fXSDErrorReporter.emitError(XMLValid::NonWSContent, XMLUni::fgValidityDomain, &fXSLocator);
467                }
468        }
469        // when it's within either of the 2 annotation subelements, characters are
470        // allowed and we need to store them.
471        else if (cdataSection)
472        {
473                fAnnotationBuf.append(XMLUni::fgCDataStart);
474                fAnnotationBuf.append(chars, length);
475                fAnnotationBuf.append(XMLUni::fgCDataEnd);
476        }
477        else
478        {
479                for (unsigned int i = 0; i < length; i++)
480                {
481                        if (chars[i] == chAmpersand)
482                        {
483                                fAnnotationBuf.append(chAmpersand);
484                                fAnnotationBuf.append(XMLUni::fgAmp);
485                                fAnnotationBuf.append(chSemiColon);
486                        }
487                        else if (chars[i] == chOpenAngle)
488                        {
489                                fAnnotationBuf.append(chAmpersand);
490                                fAnnotationBuf.append(XMLUni::fgLT);
491                                fAnnotationBuf.append(chSemiColon);
492                        }
493                        else
494                        {
495                                fAnnotationBuf.append(chars[i]);
496                        }
497                }
498        }
499}
500
501void XSDDOMParser::docComment(const XMLCh* const comment)
502{
503        if (fAnnotationDepth > -1)
504        {
505                fAnnotationBuf.append(XMLUni::fgCommentString);
506                fAnnotationBuf.append(comment);
507                fAnnotationBuf.append(chDash);
508                fAnnotationBuf.append(chDash);
509                fAnnotationBuf.append(chCloseAngle);
510        }
511}
512
513void XSDDOMParser::startEntityReference(const XMLEntityDecl&)
514{
515}
516
517void XSDDOMParser::endEntityReference(const XMLEntityDecl&)
518{
519}
520
521void XSDDOMParser::ignorableWhitespace( const XMLCh* const chars
522                                                                          , const XMLSize_t    length
523                                                                          , const bool)
524{
525        // Ignore chars before the root element
526        if (!fWithinElement || !fIncludeIgnorableWhitespace)
527                return;
528
529        if (fAnnotationDepth > -1)
530                fAnnotationBuf.append(chars, length);
531}
532
533// ---------------------------------------------------------------------------
534//  XSDDOMParser: Implementation of the XMLErrorReporter interface
535// ---------------------------------------------------------------------------
536void XSDDOMParser::error(const   unsigned int                code
537                                                 , const XMLCh* const                msgDomain
538                                                 , const XMLErrorReporter::ErrTypes  errType
539                                                 , const XMLCh* const                errorText
540                                                 , const XMLCh* const                systemId
541                                                 , const XMLCh* const                publicId
542                                                 , const XMLFileLoc                  lineNum
543                                                 , const XMLFileLoc                  colNum)
544{
545        if (errType >= XMLErrorReporter::ErrType_Fatal)
546                fSawFatal = true;
547
548        if (fUserErrorReporter)
549                fUserErrorReporter->error(code, msgDomain, errType, errorText,
550                                                                  systemId, publicId, lineNum, colNum);
551}
552
553InputSource*
554XSDDOMParser::resolveEntity(XMLResourceIdentifier* resourceIdentifier)
555{
556        if (fUserEntityHandler)
557                return fUserEntityHandler->resolveEntity(resourceIdentifier);
558
559        return 0;
560}
561
562XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.