source: icXML/icXML-devel/src/icxmlc/parsers/XMLNamespaceParser.hpp @ 3151

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

Updates for icxmlc files.

File size: 27.2 KB
Line 
1#ifndef XMLNAMESPACEPARSER_HPP
2#define XMLNAMESPACEPARSER_HPP
3
4#include <icxmlc/XMLParser.hpp>
5#include <icxmlc/parsers/XMLSchemaLoader.hpp>
6#include <icxmlc/XMLReplacementText.hpp>
7#include <icxmlc/XMLConfig.hpp>
8
9XERCES_CPP_NAMESPACE_BEGIN
10
11template<class ScannerType>
12class XMLNamespaceParser
13{
14    typedef DynamicArray<gid_t, INITIAL_ATTRIBUTE_LIST_SIZE> GidArrayType;
15
16    typedef DynamicArray<bool, INITIAL_ATTRIBUTE_LIST_SIZE> BoolArrayType;
17
18public:
19
20    inline XMLNamespaceParser
21    (
22        XMLParser &                           parser
23        , XMLNamespaceResolver &              namespaceResolver       
24        , const XMLSymbolTable &              symbolTable
25        , const XMLReferenceTable &           referenceTable
26        , XMLSchemaLoader<ScannerType> &      schemaLoader
27        , ScannerType &                       scanner
28    )         
29    : fContentStream(&parser.fContentStream[0])
30    , fCursorPtr(&parser.fContentStream[parser.fContentIdx])
31    , fCursorEndPtr(parser.fCursorEndPtr)
32    , fSymbolStream(&parser.fSymbolStream[0])
33    , fSymbolPtr(&fSymbolStream[0])
34    , fSymbolCount(parser.fSymbolCount)
35    , fReferenceStream(&parser.fReferenceStream[0])
36    , fReferencePtr(fReferenceStream)
37    , fReferenceCount(parser.fReferenceCount)
38    , fStringEndStream(&parser.fStringEndStream[0])
39    , fStringEndPtr(parser.fStringEndPtr)
40    , fStringCount(parser.fStringCount)
41    , fUriStream(parser.fUriStream)
42    , fUriPtr(&parser.fUriStream[0])
43    , fUriCount(parser.fUriCount)
44    , fContextStream(parser.fContextStream)
45    , fContextPtr(&parser.fContextStream[0])
46    , fInMarkup(parser.fInMarkup)
47    , fEndsWithPartialContent(parser.fEndsWithPartialContent)
48    , fIsXMLV1_1(scanner.getXMLVersion() == XMLReader::XMLV1_1)
49    , fMarkupCount(parser.fMarkupCount)
50    , fMaxAttributeCount(parser.fMaxAttributeCount)
51    , fMaxScope(parser.fMaxScope)
52    , fLocalPartIds(fMaxAttributeCount)
53    , fNamespaceResolver(namespaceResolver)
54    , fReferenceTable(referenceTable)
55    , fSymbolTable(symbolTable)
56    , fSchemaLoader(schemaLoader)
57    , fContainsXsiTypeOrNil(parser.fContainsXsiTypeOrNil)
58    , fScanner(scanner)
59    , fEntityContentBuffer(parser.fEntityContentBuffer)
60    {
61        DEBUG_NAMESPACE_MESSAGE("######################################################################");
62        DEBUG_NAMESPACE_MESSAGE("BEGIN NAMESPACE PROCESSING: fMarkupCount=" << fMarkupCount << " fUriCount=" << fUriCount << " fMaxScope=" << fMaxScope);
63        DEBUG_NAMESPACE_MESSAGE("######################################################################");
64
65        fContainsXsiTypeOrNil = false;
66
67        DEBUG_MESSAGE("XMLNamespaceParser::fStringCount=" << fStringCount)
68    }
69
70    inline XMLNamespaceParser
71    (
72        XMLNamespaceParser &                parser
73        , const XMLReplacementText &        entity
74    )
75    : fContentStream(entity.fContentStream)
76    , fCursorPtr(&entity.fContentStream[0])
77    , fCursorEndPtr(&entity.fContentStream[entity.fContentLength])
78    , fSymbolStream(entity.fSymbolStream)
79    , fSymbolPtr(&entity.fSymbolStream[0])
80    , fSymbolCount(entity.fSymbolCount)
81    , fReferenceStream(entity.fReferenceStream)
82    , fReferencePtr(fReferenceStream)
83    , fReferenceCount(entity.fReferenceCount)
84    , fStringEndStream(entity.fStringEndStream)
85    , fStringEndPtr(&fStringEndStream[0])
86    , fStringCount(entity.fStringEndCount)
87    , fUriStream(parser.fUriStream)
88    , fUriPtr(parser.fUriPtr)
89    , fUriCount(parser.fUriCount)
90    , fContextStream(parser.fContextStream)
91    , fContextPtr(parser.fContextPtr)
92    , fInMarkup(false)
93    , fEndsWithPartialContent(false)
94    , fIsXMLV1_1(parser.fIsXMLV1_1) // should be in the entity!
95    , fMarkupCount(entity.fMarkupCount)
96    , fMaxAttributeCount(parser.fMaxAttributeCount)
97    , fMaxScope(parser.fMaxScope)
98    , fLocalPartIds(fMaxAttributeCount)
99    , fNamespaceResolver(parser.fNamespaceResolver)
100    , fReferenceTable(parser.fReferenceTable)
101    , fSymbolTable(parser.fSymbolTable)
102    , fSchemaLoader(parser.fSchemaLoader)
103    , fContainsXsiTypeOrNil(parser.fContainsXsiTypeOrNil)
104    , fScanner(parser.fScanner)
105    , fEntityContentBuffer(parser.fEntityContentBuffer)
106    {
107        DEBUG_NAMESPACE_MESSAGE("######################################################################");
108        DEBUG_NAMESPACE_MESSAGE("BEGIN ENTITY NAMESPACE PROCESSING: " << fMarkupCount);
109        DEBUG_NAMESPACE_MESSAGE("######################################################################");
110    }
111
112    inline ~XMLNamespaceParser()
113    {
114        DEBUG_NAMESPACE_MESSAGE("######################################################################");
115        DEBUG_NAMESPACE_MESSAGE("END NAMESPACE PROCESSING: fContextIdCount=" << (fContextPtr - &fContextStream[0]));
116        DEBUG_NAMESPACE_MESSAGE("######################################################################");
117    }
118
119
120    IDISA_ALWAYS_INLINE
121    void resolveNamespaces();
122
123private:
124
125    IDISA_ALWAYS_INLINE
126    void verifyUniqueNamespacedAttributeConstraint(SymbolPtrType elementPtr, UriPtrType uriStream, const gid_t * localPartIds, const size_t attCount);
127
128    void reportUnknownPrefix(SymbolPtrType from, SymbolPtrType to);
129
130    void reportDuplicateNamespacedAttribute(SymbolPtrType elementPtr, const gid_t localPartId);
131
132    /**
133     *  Recursively resolve the namespaces of the entity
134     **/
135    void resolveEntityNamespaces(const gid_t refId);
136
137    /**
138     *  Expand any entities within an attribute value
139     **/
140    size_t expandEntitiesWithinAttributeValue(ContentPtrType & value, ContentPtrType & delimiter);
141
142    IDISA_ALWAYS_INLINE
143    void skipPastAnyEntities(ContentPtrType & delimiter);
144
145    IDISA_ALWAYS_INLINE
146    const XMLSymbol & getSymbolByPtr(SymbolPtrType symbolPtr) const;
147
148    IDISA_ALWAYS_INLINE
149    gid_t resolveAttributeUriId(const size_t index, SymbolPtrType symbolPtr, bool & isXsi, bool & namespaceContextChange, bool & speculatedCorrectly, bool & unknownPrefix);
150
151    IDISA_ALWAYS_INLINE
152    gid_t resolveEndTagUriId(SymbolPtrType symbolPtr);
153
154    IDISA_ALWAYS_INLINE
155    void writeCurrentContextId(const gid_t contextId);
156
157    void checkForXsiSchemaLocationOrNoNamespaceSchemaLocation(ContentPtrType contentStream, DelimiterPtrType delimiterStream, UriPtrType uriStream, const gid_t * localPartIds, const size_t attCount);
158
159private:
160
161    const ContentPtrType                fContentStream;
162    ContentPtrType                      fCursorPtr;
163    ContentPtrType                      fCursorEndPtr;
164
165    const SymbolPtrType                 fSymbolStream;
166    SymbolPtrType                       fSymbolPtr;
167    const size_t                        fSymbolCount;
168
169    const ReferencePtrType              fReferenceStream;
170    ReferencePtrType                    fReferencePtr;
171    const size_t                        fReferenceCount;
172
173    const DelimiterPtrType              fStringEndStream;
174    DelimiterPtrType                    fStringEndPtr;
175    const size_t &                      fStringCount;
176
177    SymbolUriArray &                                    fUriStream;
178    WritableUriPtrType                  fUriPtr;
179    const size_t                        fUriCount;
180
181    SymbolUriArray &                                    fContextStream;
182    WritableUriPtrType                  fContextPtr;
183
184    const bool                          fInMarkup;
185    const bool                          fEndsWithPartialContent;
186    const bool                          fIsXMLV1_1;
187
188    size_t                              fMarkupCount;
189    bool &                              fContainsXsiTypeOrNil;
190    const size_t                        fMaxAttributeCount;
191    const size_t                        fMaxScope;
192
193    GidArrayType                        fLocalPartIds;
194
195    XMLNamespaceResolver &              fNamespaceResolver;
196    const XMLReferenceTable &           fReferenceTable;
197    const XMLSymbolTable &              fSymbolTable;
198    XMLSchemaLoader<ScannerType> &      fSchemaLoader;
199    ScannerType &                       fScanner;
200
201    XMLBuffer * const                   fEntityContentBuffer;
202};
203
204/// --------------------------------------------------------------------------------------------------------------------------------
205
206template<class ScannerType>
207void XMLNamespaceParser<ScannerType>::resolveNamespaces()
208{
209    // this needs to record any xsi:schemaLocation | xsi:noNamespaceSchemaLocation values for the parent namespace pass to process.
210    // if there is no markup remaining, stop scanning!
211    if (unlikely(fMarkupCount == 0))
212    {
213        return;
214    }
215
216    XMLCh markupChar;   
217    switch (fInMarkup)
218    {
219        for(;;)
220        {
221    case 0: DEBUG_NAMESPACE_MESSAGE("==================================================================");               
222            DEBUG_NAMESPACE_MESSAGE(" -- atContent=" << fCursorPtr << " fMarkupCount=" << fMarkupCount << " fEndsWithPartialContent=" << fEndsWithPartialContent);
223            if (unlikely(fMarkupCount == 0 && fEndsWithPartialContent))
224            {
225                break;
226            }
227            if (1)
228            {
229                const ContentPtrType cursorPtr = fCursorPtr;
230                fCursorPtr = *fStringEndPtr++;
231                assert (cursorPtr <= fCursorPtr);
232                assert (fCursorPtr <= fCursorEndPtr);
233
234                // if we found a reference, it's a general entity. check whether it contains markup and if not, skip it.
235                // make this another template parameter? not sure if it would be useful.
236                while (unlikely(*fCursorPtr == Entity))
237                {
238                    // parse the entity and record the namespaces
239                    resolveEntityNamespaces(*fReferencePtr++);
240                    // skip to the next delimiter
241                    fCursorPtr = *fStringEndPtr++;
242                }
243                ++fCursorPtr;
244            }
245    case 1: if (unlikely(fMarkupCount == 0))
246            {
247                break;
248            }
249            // advance past the trailing null char and process the next markup element
250            markupChar = *fCursorPtr;
251            {
252                bool hasAttributes = 0;
253                switch (markupChar & MarkupMask)
254                {
255                    /// ------------------------------------------------------------------------ ///
256                    case StartTagWithAttributes:
257                        hasAttributes = 1;
258                    case StartTagWithoutAttributes:
259                    {
260                        // a new namespaces is possible here! speculate that any unknown ones are acceptable, but
261                        // verify after the fact if any new ones occured.
262                        fNamespaceResolver.enterScope();
263                        const SymbolPtrType elementSymbolPtr = fSymbolPtr;
264                        const WritableUriPtrType elementUriPtr = fUriPtr;
265                        bool unknownPrefix = 0;
266                        bool namespaceContextChange = 0;
267
268                        if (hasAttributes)
269                        {
270                            const ContentPtrType initialCursorPtr = fCursorPtr;
271                            const DelimiterPtrType initialStringEndPtr = fStringEndPtr;
272
273                            for (;;)
274                            {
275                                bool observedXsi = 0;
276                                bool speculatedCorrectly = 1;
277                                size_t attCount = 0;
278
279                                do
280                                {
281                                    /// --------------------------------------------------------------------------------------------------------------
282                                    /// DOCUMENT ATTRIBUTE RESOLUTION
283                                    /// --------------------------------------------------------------------------------------------------------------
284
285                                    // extract the next attribute ...
286
287                                    *++fUriPtr = resolveAttributeUriId(attCount++, ++fSymbolPtr, observedXsi, namespaceContextChange, speculatedCorrectly, unknownPrefix);
288
289                                    // if the next markup char's value is 0 (8), then we're at the end of the start/empty tag
290                                    markupChar = *++fCursorPtr;
291                                }
292                                while ((markupChar & MarkupMask) == Attribute);
293
294                                /// --------------------------------------------------------------------------------------------------------------
295                                /// Default attribute resolution was performed in well-formedness checker
296                                /// --------------------------------------------------------------------------------------------------------------
297
298                                if (likely(speculatedCorrectly))
299                                {
300                                    verifyUniqueNamespacedAttributeConstraint(elementSymbolPtr, elementUriPtr + 1, &fLocalPartIds[0], attCount);
301
302                                    if (unlikely(observedXsi))
303                                    {
304                                        checkForXsiSchemaLocationOrNoNamespaceSchemaLocation(initialCursorPtr, initialStringEndPtr, elementUriPtr + 1, &fLocalPartIds[0], attCount);
305                                    }
306
307                                    // if we speculated correctly, then any 'unknown' prefix was found to be what we predicted it would be.
308                                    unknownPrefix &= !namespaceContextChange;
309
310                                    break;
311                                }
312                                else // note: this code can only be entered once. it is impossible to misspeculate a second time.
313                                {
314                                    DEBUG_NAMESPACE_MESSAGE("------------------------------------------------------------------");
315                                    DEBUG_NAMESPACE_MESSAGE(" *** uri speculation failed! retrying!");
316                                    DEBUG_NAMESPACE_MESSAGE("==================================================================");
317
318                                    fNamespaceResolver.misspeculated();
319                                    fCursorPtr = initialCursorPtr;
320                                    fSymbolPtr = elementSymbolPtr;
321                                    fUriPtr = elementUriPtr;
322                                    fStringEndPtr = initialStringEndPtr;
323                                    unknownPrefix = 0;
324                                }
325                            }
326
327                        }
328
329                        const XMLSymbol & element = getSymbolByPtr(elementSymbolPtr);
330                        if (unlikely(element.isXMLNS()))
331                        {
332                            fScanner.emitError(XMLErrs::NoXMLNSAsElementPrefix, element.getName());
333                        }
334
335                        // resolve the uri of the element and test whether there are any unknown prefiexes
336
337                        *elementUriPtr = fNamespaceResolver.resolveUriId(element, false, unknownPrefix);
338
339                        const bool isEmpty = (markupChar >> 3);
340
341                        ++fCursorPtr;
342                        ++fSymbolPtr;
343                        ++fUriPtr;
344                        *fContextPtr++ = fNamespaceResolver.finalizeScope(namespaceContextChange);
345
346                        DEBUG_NAMESPACE_MESSAGE
347                        (
348                            (isEmpty ? " --- atEmptyTag: " : " --- atStartTag: ") << element
349                            << " scope=" << fNamespaceResolver.getScope()
350                            << " uriId=" << *elementUriPtr
351                            << " unknownPrefix=" << unknownPrefix
352                            << " namespaceContextChange=" << namespaceContextChange
353                            << " markupCount=" << fMarkupCount
354                        );
355
356                        if (unlikely(unknownPrefix))
357                        {
358                            reportUnknownPrefix(elementSymbolPtr, fSymbolPtr);
359                        }
360
361                        // outdent scope by one if and only if this element is an empty tag
362                        if (isEmpty)
363                        {
364                            fNamespaceResolver.leaveScope(namespaceContextChange);
365                        }
366                        break;
367                    }
368                    /// ------------------------------------------------------------------------ ///
369                    case EndTag:
370                    {
371                        *fUriPtr = resolveEndTagUriId(fSymbolPtr);
372
373                        DEBUG_NAMESPACE_MESSAGE
374                        (
375                            " --- atEndTag: " << getSymbolByPtr(fSymbolPtr)
376                            << " scope=" << fNamespaceResolver.getScope()
377                            << " uriId=" << *fUriPtr
378                            << " markupCount=" << fMarkupCount
379                        );
380
381                        fCursorPtr++;
382                        fUriPtr++;
383                        fSymbolPtr++;
384                        bool namespaceContextChange;
385                        *fContextPtr++ = fNamespaceResolver.leaveScope(namespaceContextChange);
386                        break;
387                    }
388                    /// ------------------------------------------------------------------------ ///
389                    case ProcessingInstruction:
390                        fStringEndPtr++; // skip the target name
391                    case Comment:
392                    case CDATA:
393                        fStringEndPtr++; // skip the value
394                        break;
395                    default:
396                        UNREACHABLE
397                /// ------------------------------------------------------------------------ ///
398                }
399            }
400            --fMarkupCount;
401        }       
402    }
403}
404
405/// --------------------------------------------------------------------------------------------------------------------------------
406
407template<class ScannerType>
408const XMLSymbol & XMLNamespaceParser<ScannerType>::getSymbolByPtr(SymbolPtrType symbolPtr) const
409{
410    return fSymbolTable[*symbolPtr];
411}
412
413/// --------------------------------------------------------------------------------------------------------------------------------
414
415template<class ScannerType>
416gid_t XMLNamespaceParser<ScannerType>::
417resolveAttributeUriId(const size_t index, SymbolPtrType symbolPtr, bool & observedXsi, bool & namespaceContextChange, bool & speculatedCorrectly, bool & unknownPrefix)
418{
419    const XMLSymbol & attribute = getSymbolByPtr(symbolPtr);
420
421    // advance past the '=' and determine the length of the attribute value from the delimiter ptr
422    ContentPtrType value = ++fCursorPtr;
423    ContentPtrType delimiter = *fStringEndPtr++;
424
425    gid_t uriId;
426    // is this an "xmlns" attribute? if so, then we want to update the namespace table.
427    if (unlikely(attribute.isXMLNS()))
428    {
429        size_t length;
430        bool expanded = false;
431        // expand any entities within the URI string.
432        if (unlikely(*delimiter == Entity))
433        {
434            length = expandEntitiesWithinAttributeValue(value, delimiter);
435            expanded = true;
436        }
437        else
438        {
439            length = delimiter - value;
440        }
441
442        XMLErrs::Codes bindingError = XMLErrs::NoError;
443        uriId = fNamespaceResolver.bindNamespace(attribute, value, length, fIsXMLV1_1, speculatedCorrectly, namespaceContextChange, bindingError);
444        if (unlikely(bindingError != XMLErrs::NoError))
445        {
446            fScanner.emitError(bindingError, attribute.getQName()->getRawName());
447        }
448
449        // mark any attribute as either a namespace or surpressed attribute; this will inform the DocumentAccumulator as to whether or not
450        // to include the xmlns attribute in the document context and object streams.
451        const static MarkupType attributeType[2] = { Surpressed, NamespaceAttribute };
452        WritableContentPtrType attributeMarker = const_cast<WritableContentPtrType>(fCursorPtr - 1);
453        *attributeMarker = (*attributeMarker & DefaultAttribute) | attributeType[namespaceContextChange];
454
455        if (unlikely(expanded))
456        {
457            fEntityContentBuffer->reset();
458        }
459
460        DEBUG_NAMESPACE_MESSAGE(" --- atAttribute" << (index + 1) << ' ' << getSymbolByPtr(fSymbolPtr) << '=' << value << " uriId=" << uriId << " speculatedCorrectly=" << speculatedCorrectly);
461    }
462    else // just resolve the uri gid
463    {
464        uriId = fNamespaceResolver.resolveUriId(attribute, true, unknownPrefix);
465        DEBUG_NAMESPACE_MESSAGE(" --- atAttribute" << (index + 1) << ' ' << getSymbolByPtr(fSymbolPtr) << '=' << value << " uriId=" << uriId << " observedXsi=" << observedXsi << " unknownPrefix=" << unknownPrefix);
466        observedXsi |= (uriId == XMLNamespaceResolver::fSchemaInstanceUriId);
467        // skip past any entity; we don't care about the actual value unless it's an URI.
468        skipPastAnyEntities(delimiter);
469    }
470
471    // record the localPartId for this attribute and its value
472    fLocalPartIds[index] = attribute.getLocalPartId();
473
474    fCursorPtr = delimiter;
475
476    return uriId;
477}
478
479/// --------------------------------------------------------------------------------------------------------------------------------
480
481template<class ScannerType>
482size_t XMLNamespaceParser<ScannerType>::
483expandEntitiesWithinAttributeValue(ContentPtrType & value, ContentPtrType & delimiter)
484{
485    fEntityContentBuffer->set(value, delimiter - value);
486    do
487    {
488        const XMLReplacementText & entity = fReferenceTable[*fReferencePtr++];
489        fEntityContentBuffer->append(entity.fContentStream, entity.fContentLength);
490        value = delimiter + 1;
491        delimiter = *fStringEndPtr++;
492        assert (value <= delimiter);
493        // append either the posterior content of this attribute value or any content between two entities
494        fEntityContentBuffer->append(value, delimiter - value);
495    }
496    while (*delimiter == Entity);
497    value = fEntityContentBuffer->getRawBuffer();
498    return fEntityContentBuffer->getLen();
499}
500
501/// --------------------------------------------------------------------------------------------------------------------------------
502
503template<class ScannerType>
504void XMLNamespaceParser<ScannerType>::
505skipPastAnyEntities(ContentPtrType & delimiter)
506{
507    while (unlikely(*delimiter == Entity))
508    {
509        assert (delimiter < *fStringEndPtr);
510        delimiter = *fStringEndPtr++;
511        assert (&fContentStream[0] < delimiter);
512        // skip this reference
513        fReferencePtr++;
514    }
515}
516
517/// --------------------------------------------------------------------------------------------------------------------------------
518
519template<class ScannerType>
520gid_t XMLNamespaceParser<ScannerType>::
521resolveEndTagUriId(SymbolPtrType symbolPtr)
522{
523    bool unknownPrefix;
524    return fNamespaceResolver.resolveUriId(getSymbolByPtr(symbolPtr), false, unknownPrefix);
525}
526
527/// --------------------------------------------------------------------------------------------------------------------------------
528/// ENTITY HANDLING FUNCTIONS
529/// --------------------------------------------------------------------------------------------------------------------------------
530
531template<class ScannerType>
532void XMLNamespaceParser<ScannerType>::
533resolveEntityNamespaces(const gid_t refId)
534{
535    const XMLReplacementText & entity = fReferenceTable[refId];
536    if (unlikely(entity.getMarkupCount() != 0))
537    {
538        XMLNamespaceParser<ScannerType> parser(*this, entity);
539        parser.resolveNamespaces();
540        // update the internal indexes based on what the parser resolved.
541        fUriPtr = parser.fUriPtr;
542        fContextPtr = parser.fContextPtr;
543
544        DEBUG_NAMESPACE_MESSAGE("######################################################################");
545        DEBUG_NAMESPACE_MESSAGE("END ENTITY NAMESPACE PROCESSING: " << fMarkupCount);
546        DEBUG_NAMESPACE_MESSAGE("######################################################################");
547    }
548}
549
550
551/// --------------------------------------------------------------------------------------------------------------------------------
552/// ERROR HANDLING FUNCTIONS
553/// --------------------------------------------------------------------------------------------------------------------------------
554
555template<class ScannerType>
556void XMLNamespaceParser<ScannerType>::
557reportUnknownPrefix(SymbolPtrType from, SymbolPtrType to)
558{
559    for (; from <= to; from++)
560    {
561        const XMLSymbol & symbol = getSymbolByPtr(from);
562        DEBUG_MESSAGE("symbol=" << symbol)
563
564        if (!fNamespaceResolver.isPrefixVisible(symbol.getPrefixId()))
565        {
566            fScanner.emitError(XMLErrs::UnknownPrefix, symbol.getQName()->getPrefix());
567        }
568    }
569}
570
571/*
572    Namespaces in XML 1.0 (Third Edition)
573
574        6.3 Uniqueness of Attributes
575
576        Namespace constraint: Attributes Unique
577        In XML documents conforming to this specification, no tag may contain two attributes which:
578            have identical names, or
579            have qualified names with the same local part and with prefixes which have been bound to namespace
580            names that are identical.
581*/
582
583template<class ScannerType>
584void XMLNamespaceParser<ScannerType>::
585verifyUniqueNamespacedAttributeConstraint(SymbolPtrType elementPtr, UriPtrType uriStream, const gid_t * localPartIds, const size_t attCount)
586{
587    // find a better way to do this; there must be some O(N) method in which the constant factor is < 3.
588    // if not would it be better to
589
590    for (size_t i = 1; i < attCount; i++)
591    {
592        const gid_t localPartId = localPartIds[i];
593
594        for (size_t j = 0; j < i; j++)
595        {
596            if (unlikely(localPartIds[j] == localPartId))
597            {
598                if (unlikely(uriStream[j] == uriStream[i]))
599                {
600                    reportDuplicateNamespacedAttribute(elementPtr, localPartId);
601                }
602            }
603        }
604    }
605}
606
607template<class ScannerType>
608void XMLNamespaceParser<ScannerType>::
609checkForXsiSchemaLocationOrNoNamespaceSchemaLocation(ContentPtrType contentStream, DelimiterPtrType delimiterStream, UriPtrType uriStream, const gid_t * localPartIds, const size_t attCount)
610{
611    // is this an "xsi:schemaLocation" or "xsi:noNamespaceSchemaLocation" attribute? if so, then
612    // record it as something to load later.
613
614    for (size_t i = 0; i < attCount; i++)
615    {
616        // advance past the '=' and determine the length of the attribute value from the delimiter ptr
617        const size_t length = *delimiterStream - ++contentStream;
618
619        if (uriStream[i] == XMLNamespaceResolver::fSchemaInstanceUriId)
620        {
621            bool noNamespace = 1;
622            switch (localPartIds[i])
623            {
624                case XMLSymbolTable::Type:
625                case XMLSymbolTable::Nil:
626                    fContainsXsiTypeOrNil = true;
627                    break;
628                case XMLSymbolTable::SchemaLocation:
629                    noNamespace = 0;
630                case XMLSymbolTable::NoNamespaceSchemaLocation:
631                    fSchemaLoader.addSchema(contentStream, length, noNamespace);
632            }
633        }
634        contentStream = *delimiterStream++ + 1;
635    }
636}
637
638template<class ScannerType>
639void XMLNamespaceParser<ScannerType>::
640reportDuplicateNamespacedAttribute(SymbolPtrType elementPtr, const gid_t localPartId)
641{
642    fScanner.emitError(XMLErrs::AttrAlreadyUsedInSTag, fSymbolTable.getNCName(localPartId), getSymbolByPtr(elementPtr).getName());
643}
644
645XERCES_CPP_NAMESPACE_END
646
647#endif // XMLNAMESPACEPARSER_HPP
Note: See TracBrowser for help on using the repository browser.