9467 lines
352 KiB
C++
9467 lines
352 KiB
C++
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
* (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
* $Id: TraverseSchema.cpp 1141162 2011-06-29 16:48:30Z borisk $
|
|
*/
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Includes
|
|
// ---------------------------------------------------------------------------
|
|
#include <xercesc/validators/schema/TraverseSchema.hpp>
|
|
#include <xercesc/framework/XMLEntityHandler.hpp>
|
|
#include <xercesc/framework/XMLValidityCodes.hpp>
|
|
#include <xercesc/validators/schema/identity/IC_Key.hpp>
|
|
#include <xercesc/validators/schema/identity/IC_KeyRef.hpp>
|
|
#include <xercesc/validators/schema/identity/IC_Unique.hpp>
|
|
#include <xercesc/validators/schema/identity/IC_Field.hpp>
|
|
#include <xercesc/validators/schema/identity/IC_Selector.hpp>
|
|
#include <xercesc/validators/schema/identity/XercesXPath.hpp>
|
|
#include <xercesc/util/XMLStringTokenizer.hpp>
|
|
#include <xercesc/validators/schema/XUtil.hpp>
|
|
#include <xercesc/validators/common/GrammarResolver.hpp>
|
|
#include <xercesc/internal/XMLReader.hpp>
|
|
#include <xercesc/validators/schema/ComplexTypeInfo.hpp>
|
|
#include <xercesc/validators/schema/NamespaceScope.hpp>
|
|
#include <xercesc/validators/schema/SchemaAttDefList.hpp>
|
|
#include <xercesc/internal/XMLScanner.hpp>
|
|
#include <xercesc/framework/LocalFileInputSource.hpp>
|
|
#include <xercesc/framework/URLInputSource.hpp>
|
|
#include <xercesc/framework/XMLGrammarPool.hpp>
|
|
#include <xercesc/framework/XMLSchemaDescription.hpp>
|
|
#include <xercesc/validators/schema/identity/XPathException.hpp>
|
|
#include <xercesc/validators/schema/GeneralAttributeCheck.hpp>
|
|
#include <xercesc/validators/schema/XercesGroupInfo.hpp>
|
|
#include <xercesc/validators/schema/XercesAttGroupInfo.hpp>
|
|
#include <xercesc/validators/schema/XSDLocator.hpp>
|
|
#include <xercesc/validators/schema/XSDDOMParser.hpp>
|
|
#include <xercesc/dom/DOMNamedNodeMap.hpp>
|
|
#include <xercesc/dom/DOMText.hpp>
|
|
#include <xercesc/dom/impl/XSDElementNSImpl.hpp>
|
|
#include <xercesc/util/OutOfMemoryException.hpp>
|
|
#include <xercesc/util/NumberFormatException.hpp>
|
|
#include <xercesc/util/XMLEntityResolver.hpp>
|
|
#include <xercesc/util/XMLUri.hpp>
|
|
#include <xercesc/framework/psvi/XSAnnotation.hpp>
|
|
#include <xercesc/framework/MemBufInputSource.hpp>
|
|
#include <xercesc/internal/XSAXMLScanner.hpp>
|
|
|
|
XERCES_CPP_NAMESPACE_BEGIN
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// TraverseSchema: Local declaration
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// This helper class will handle the parsing of namespace prefixes for a given DOMElement, and its winding back
|
|
class NamespaceScopeManager
|
|
{
|
|
public:
|
|
NamespaceScopeManager(const DOMElement* const node, SchemaInfo* info, TraverseSchema* traverser)
|
|
{
|
|
fScopeAdded=node?traverser->retrieveNamespaceMapping(node):false;
|
|
fSchemaInfo=info;
|
|
}
|
|
~NamespaceScopeManager()
|
|
{
|
|
if(fScopeAdded)
|
|
fSchemaInfo->getNamespaceScope()->decreaseDepth();
|
|
|
|
}
|
|
protected:
|
|
bool fScopeAdded;
|
|
SchemaInfo* fSchemaInfo;
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// TraverseSchema: Static member data
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// TraverseSchema: Local const data
|
|
// ---------------------------------------------------------------------------
|
|
static const XMLCh fgAnonSNamePrefix[] =
|
|
{
|
|
chUnderscore, chUnderscore, chLatin_A, chLatin_n, chLatin_o, chLatin_n, chLatin_S, chNull
|
|
};
|
|
|
|
static const XMLCh fgAnonCNamePrefix[] =
|
|
{
|
|
chUnderscore, chUnderscore, chLatin_A, chLatin_n, chLatin_o, chLatin_n, chLatin_C, chNull
|
|
};
|
|
|
|
static const XMLCh fgUnbounded[] =
|
|
{
|
|
chLatin_u, chLatin_n, chLatin_b, chLatin_o, chLatin_u, chLatin_n, chLatin_d,
|
|
chLatin_e, chLatin_d, chNull
|
|
};
|
|
|
|
static const XMLCh fgValueOne[] =
|
|
{
|
|
chDigit_1, chNull
|
|
};
|
|
|
|
static const XMLCh fgValueZero[] =
|
|
{
|
|
chDigit_0, chNull
|
|
};
|
|
|
|
static const XMLCh* fgIdentityConstraints[] =
|
|
{
|
|
SchemaSymbols::fgELT_UNIQUE,
|
|
SchemaSymbols::fgELT_KEY,
|
|
SchemaSymbols::fgELT_KEYREF
|
|
};
|
|
|
|
static const XMLCh fgSynthetic_Annotation[] =
|
|
{
|
|
chLatin_S, chLatin_y, chLatin_n, chLatin_t, chLatin_h, chLatin_e, chLatin_t
|
|
, chLatin_i, chLatin_c, chUnderscore
|
|
, chLatin_A, chLatin_n, chLatin_n, chLatin_o, chLatin_t, chLatin_a, chLatin_t
|
|
, chLatin_i, chLatin_o, chLatin_n, chNull
|
|
};
|
|
|
|
|
|
// Flags for global declaration
|
|
enum {
|
|
ENUM_ELT_SIMPLETYPE,
|
|
ENUM_ELT_COMPLEXTYPE,
|
|
ENUM_ELT_ELEMENT,
|
|
ENUM_ELT_ATTRIBUTE,
|
|
ENUM_ELT_ATTRIBUTEGROUP,
|
|
ENUM_ELT_GROUP,
|
|
ENUM_ELT_SIZE
|
|
};
|
|
|
|
typedef JanitorMemFunCall<TraverseSchema> CleanupType;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// TraverseSchema: Constructors and Destructor
|
|
// ---------------------------------------------------------------------------
|
|
TraverseSchema::TraverseSchema( DOMElement* const schemaRoot
|
|
, XMLStringPool* const uriStringPool
|
|
, SchemaGrammar* const schemaGrammar
|
|
, GrammarResolver* const grammarResolver
|
|
, RefHash2KeysTableOf<SchemaInfo>* cachedSchemaInfoList
|
|
, RefHash2KeysTableOf<SchemaInfo>* schemaInfoList
|
|
, XMLScanner* const xmlScanner
|
|
, const XMLCh* const schemaURL
|
|
, XMLEntityHandler* const entityHandler
|
|
, XMLErrorReporter* const errorReporter
|
|
, MemoryManager* const manager
|
|
, bool multipleImport)
|
|
: fFullConstraintChecking(false)
|
|
, fTargetNSURI(-1)
|
|
, fEmptyNamespaceURI(-1)
|
|
, fCurrentScope(Grammar::TOP_LEVEL_SCOPE)
|
|
, fScopeCount(schemaGrammar->getScopeCount ())
|
|
, fAnonXSTypeCount(schemaGrammar->getAnonTypeCount ())
|
|
, fCircularCheckIndex(0)
|
|
, fTargetNSURIString(0)
|
|
, fDatatypeRegistry(0)
|
|
, fGrammarResolver(grammarResolver)
|
|
, fSchemaGrammar(schemaGrammar)
|
|
, fEntityHandler(entityHandler)
|
|
, fErrorReporter(errorReporter)
|
|
, fURIStringPool(uriStringPool)
|
|
, fStringPool(0)
|
|
, fBuffer(1023, manager)
|
|
, fScanner(xmlScanner)
|
|
, fAttributeDeclRegistry(0)
|
|
, fComplexTypeRegistry(0)
|
|
, fGroupRegistry(0)
|
|
, fAttGroupRegistry(0)
|
|
, fIC_ElementsNS(0)
|
|
, fPreprocessedNodes(0)
|
|
, fSchemaInfo(0)
|
|
, fCurrentGroupInfo(0)
|
|
, fCurrentAttGroupInfo(0)
|
|
, fCurrentComplexType(0)
|
|
, fCurrentTypeNameStack(0)
|
|
, fCurrentGroupStack(0)
|
|
, fIC_Elements(0)
|
|
, fDeclStack(0)
|
|
, fGlobalDeclarations(0)
|
|
, fNonXSAttList(0)
|
|
, fImportedNSList(0)
|
|
, fIC_NodeListNS(0)
|
|
, fNotationRegistry(0)
|
|
, fRedefineComponents(0)
|
|
, fIdentityConstraintNames(0)
|
|
, fValidSubstitutionGroups(0)
|
|
, fSchemaInfoList(schemaInfoList)
|
|
, fCachedSchemaInfoList (cachedSchemaInfoList)
|
|
, fParser(0)
|
|
, fLocator(0)
|
|
, fMemoryManager(manager)
|
|
, fGrammarPoolMemoryManager(fGrammarResolver->getGrammarPoolMemoryManager())
|
|
, fAnnotation(0)
|
|
, fAttributeCheck(manager)
|
|
{
|
|
CleanupType cleanup(this, &TraverseSchema::cleanUp);
|
|
|
|
try {
|
|
|
|
if (fGrammarResolver && schemaRoot && fURIStringPool) {
|
|
|
|
init();
|
|
|
|
if (multipleImport)
|
|
{
|
|
// If we are working on an existing schema, do some
|
|
// intitialization that is otherwise done by preprocessSchema.
|
|
//
|
|
fComplexTypeRegistry = fSchemaGrammar->getComplexTypeRegistry();
|
|
fGroupRegistry = fSchemaGrammar->getGroupInfoRegistry();
|
|
fAttGroupRegistry = fSchemaGrammar->getAttGroupInfoRegistry();
|
|
fAttributeDeclRegistry = fSchemaGrammar->getAttributeDeclRegistry();
|
|
fValidSubstitutionGroups = fSchemaGrammar->getValidSubstitutionGroups();
|
|
}
|
|
|
|
preprocessSchema(schemaRoot, schemaURL, multipleImport);
|
|
doTraverseSchema(schemaRoot);
|
|
|
|
// Store the scope and anon type counts in case we need to add
|
|
// more to this grammar (multi-import case). schemaGrammar and
|
|
// fSchemaGrammar should be the same here.
|
|
//
|
|
fSchemaGrammar->setScopeCount (fScopeCount);
|
|
fSchemaGrammar->setAnonTypeCount (fAnonXSTypeCount);
|
|
}
|
|
|
|
}
|
|
catch(const OutOfMemoryException&)
|
|
{
|
|
cleanup.release();
|
|
|
|
throw;
|
|
}
|
|
|
|
cleanup.release();
|
|
}
|
|
|
|
|
|
TraverseSchema::~TraverseSchema()
|
|
{
|
|
cleanUp();
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// TraverseSchema: Traversal methods
|
|
// ---------------------------------------------------------------------------
|
|
void TraverseSchema::doTraverseSchema(const DOMElement* const schemaRoot) {
|
|
|
|
// process children nodes
|
|
processChildren(schemaRoot);
|
|
|
|
// Handle identity constraints - keyref
|
|
if (fIC_ElementsNS && fIC_ElementsNS->containsKey(fTargetNSURIString)) {
|
|
|
|
fIC_Elements = fIC_ElementsNS->get(fTargetNSURIString);
|
|
|
|
XMLSize_t icListSize = fIC_Elements->size();
|
|
|
|
for (XMLSize_t i=0; i < icListSize; i++) {
|
|
|
|
SchemaElementDecl* curElem = fIC_Elements->elementAt(i);
|
|
ValueVectorOf<DOMElement*>* icNodes = fIC_NodeListNS->get(curElem);
|
|
XMLSize_t icNodesSize = icNodes->size();
|
|
|
|
for (XMLSize_t j = 0; j < icNodesSize; j++) {
|
|
traverseKeyRef(icNodes->elementAt(j), curElem);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fScanner->getValidateAnnotations() && !fSchemaGrammar->getAnnotations()->isEmpty())
|
|
{
|
|
validateAnnotations();
|
|
}
|
|
fSchemaInfo->setProcessed();
|
|
}
|
|
|
|
void TraverseSchema::preprocessSchema(DOMElement* const schemaRoot,
|
|
const XMLCh* const schemaURL,
|
|
bool multipleImport) {
|
|
if (!multipleImport) {
|
|
// Make sure namespace binding is defaulted
|
|
const XMLCh* rootPrefix = schemaRoot->getPrefix();
|
|
|
|
if (rootPrefix == 0 || !*rootPrefix) {
|
|
|
|
const XMLCh* xmlnsStr = schemaRoot->getAttribute(XMLUni::fgXMLNSString);
|
|
|
|
if (!xmlnsStr || !*xmlnsStr) {
|
|
schemaRoot->setAttribute(XMLUni::fgXMLNSString, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
|
|
}
|
|
}
|
|
|
|
// Set schemaGrammar data and add it to GrammarResolver
|
|
// For complex type registry, attribute decl registry , group/attGroup
|
|
// and namespace mapping, needs to check whether the passed in
|
|
// Grammar was a newly instantiated one.
|
|
fComplexTypeRegistry = fSchemaGrammar->getComplexTypeRegistry();
|
|
|
|
if (fComplexTypeRegistry == 0 ) {
|
|
|
|
fComplexTypeRegistry = new (fGrammarPoolMemoryManager) RefHashTableOf<ComplexTypeInfo>(29, fGrammarPoolMemoryManager);
|
|
fSchemaGrammar->setComplexTypeRegistry(fComplexTypeRegistry);
|
|
}
|
|
|
|
fGroupRegistry = fSchemaGrammar->getGroupInfoRegistry();
|
|
|
|
if (fGroupRegistry == 0 ) {
|
|
|
|
fGroupRegistry = new (fGrammarPoolMemoryManager) RefHashTableOf<XercesGroupInfo>(13, fGrammarPoolMemoryManager);
|
|
fSchemaGrammar->setGroupInfoRegistry(fGroupRegistry);
|
|
}
|
|
|
|
fAttGroupRegistry = fSchemaGrammar->getAttGroupInfoRegistry();
|
|
|
|
if (fAttGroupRegistry == 0 ) {
|
|
|
|
fAttGroupRegistry = new (fGrammarPoolMemoryManager) RefHashTableOf<XercesAttGroupInfo>(13, fGrammarPoolMemoryManager);
|
|
fSchemaGrammar->setAttGroupInfoRegistry(fAttGroupRegistry);
|
|
}
|
|
|
|
fAttributeDeclRegistry = fSchemaGrammar->getAttributeDeclRegistry();
|
|
|
|
if (fAttributeDeclRegistry == 0) {
|
|
|
|
fAttributeDeclRegistry = new (fGrammarPoolMemoryManager) RefHashTableOf<XMLAttDef>(29, fGrammarPoolMemoryManager);
|
|
fSchemaGrammar->setAttributeDeclRegistry(fAttributeDeclRegistry);
|
|
}
|
|
|
|
fValidSubstitutionGroups = fSchemaGrammar->getValidSubstitutionGroups();
|
|
|
|
if (!fValidSubstitutionGroups) {
|
|
|
|
fValidSubstitutionGroups = new (fGrammarPoolMemoryManager) RefHash2KeysTableOf<ElemVector>(29, fGrammarPoolMemoryManager);
|
|
fSchemaGrammar->setValidSubstitutionGroups(fValidSubstitutionGroups);
|
|
}
|
|
|
|
//Retrieve the targetnamespace URI information
|
|
const XMLCh* targetNSURIStr = schemaRoot->getAttribute(SchemaSymbols::fgATT_TARGETNAMESPACE);
|
|
fSchemaGrammar->setTargetNamespace(targetNSURIStr);
|
|
|
|
fCurrentScope = Grammar::TOP_LEVEL_SCOPE;
|
|
fTargetNSURIString = fSchemaGrammar->getTargetNamespace();
|
|
fTargetNSURI = fURIStringPool->addOrFind(fTargetNSURIString);
|
|
|
|
XMLSchemaDescription* gramDesc = (XMLSchemaDescription*) fSchemaGrammar->getGrammarDescription();
|
|
gramDesc->setTargetNamespace(fTargetNSURIString);
|
|
|
|
fGrammarResolver->putGrammar(fSchemaGrammar);
|
|
}
|
|
else {
|
|
fCurrentScope = Grammar::TOP_LEVEL_SCOPE;
|
|
|
|
fTargetNSURIString = fSchemaGrammar->getTargetNamespace();
|
|
fTargetNSURI = fURIStringPool->addOrFind(fTargetNSURIString);
|
|
}
|
|
|
|
SchemaInfo* currInfo = new (fMemoryManager) SchemaInfo(0, 0, 0, fTargetNSURI,
|
|
0,
|
|
schemaURL,
|
|
fTargetNSURIString, schemaRoot,
|
|
fScanner,
|
|
fGrammarPoolMemoryManager);
|
|
|
|
currInfo->getNamespaceScope()->reset(fEmptyNamespaceURI);
|
|
// Add mapping for the xml prefix
|
|
currInfo->getNamespaceScope()->addPrefix(XMLUni::fgXMLString, fURIStringPool->addOrFind(XMLUni::fgXMLURIName));
|
|
|
|
if (fSchemaInfo)
|
|
fSchemaInfo->addSchemaInfo(currInfo, SchemaInfo::IMPORT);
|
|
|
|
addImportedNS(currInfo->getTargetNSURI());
|
|
|
|
fSchemaInfo = currInfo;
|
|
fSchemaInfoList->put((void*) fSchemaInfo->getCurrentSchemaURL(), fSchemaInfo->getTargetNSURI(), fSchemaInfo);
|
|
fSchemaInfo->addSchemaInfo(fSchemaInfo, SchemaInfo::INCLUDE);
|
|
traverseSchemaHeader(schemaRoot);
|
|
|
|
// preprocess chidren
|
|
preprocessChildren(schemaRoot);
|
|
}
|
|
|
|
|
|
void TraverseSchema::traverseSchemaHeader(const DOMElement* const schemaRoot) {
|
|
|
|
// Make sure that the root element is <xsd:schema>
|
|
if (!XMLString::equals(schemaRoot->getLocalName(), SchemaSymbols::fgELT_SCHEMA)) {
|
|
reportSchemaError(schemaRoot, XMLUni::fgXMLErrDomain, XMLErrs::InvalidXMLSchemaRoot);
|
|
}
|
|
|
|
// Make sure that the targetNamespace value is not empty string
|
|
checkForEmptyTargetNamespace(schemaRoot);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check Attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
schemaRoot, GeneralAttributeCheck::E_Schema, this
|
|
, true, fSchemaInfo->getNonXSAttList()
|
|
);
|
|
|
|
retrieveNamespaceMapping(schemaRoot);
|
|
// Add mapping for the default namespace
|
|
if ((!fTargetNSURIString || !*fTargetNSURIString) && schemaRoot->getAttributeNode(XMLUni::fgXMLNSString)==NULL)
|
|
fSchemaInfo->getNamespaceScope()->addPrefix(XMLUni::fgZeroLenString, fEmptyNamespaceURI);
|
|
|
|
unsigned short elemAttrDefaultQualified = 0;
|
|
|
|
if (XMLString::equals(schemaRoot->getAttribute(SchemaSymbols::fgATT_ELEMENTFORMDEFAULT),
|
|
SchemaSymbols::fgATTVAL_QUALIFIED)) {
|
|
elemAttrDefaultQualified |= Elem_Def_Qualified;
|
|
}
|
|
|
|
if (XMLString::equals(schemaRoot->getAttribute(SchemaSymbols::fgATT_ATTRIBUTEFORMDEFAULT),
|
|
SchemaSymbols::fgATTVAL_QUALIFIED)) {
|
|
elemAttrDefaultQualified |= Attr_Def_Qualified;
|
|
}
|
|
|
|
fSchemaInfo->setElemAttrDefaultQualified(elemAttrDefaultQualified);
|
|
fSchemaInfo->setBlockDefault(parseBlockSet(schemaRoot, ES_Block, true));
|
|
fSchemaInfo->setFinalDefault(parseFinalSet(schemaRoot, ECS_Final, true));
|
|
}
|
|
|
|
|
|
XSAnnotation*
|
|
TraverseSchema::traverseAnnotationDecl(const DOMElement* const annotationElem,
|
|
ValueVectorOf<DOMNode*>* const nonXSAttList,
|
|
const bool topLevel) {
|
|
|
|
NamespaceScopeManager nsMgr(annotationElem, fSchemaInfo, this);
|
|
// -----------------------------------------------------------------------
|
|
// Check Attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
annotationElem, GeneralAttributeCheck::E_Annotation, this, topLevel
|
|
);
|
|
|
|
const XMLCh* contents = 0;
|
|
DOMElement* child = XUtil::getFirstChildElement(annotationElem);
|
|
if (child) {
|
|
for (;
|
|
child != 0;
|
|
child = XUtil::getNextSiblingElement(child)) {
|
|
|
|
const XMLCh* name = child->getLocalName();
|
|
|
|
if (XMLString::equals(name, SchemaSymbols::fgELT_APPINFO)) {
|
|
|
|
DOMNode* textContent = child->getFirstChild();
|
|
if (textContent && textContent->getNodeType() == DOMNode::TEXT_NODE)
|
|
contents = ((DOMText*) textContent)->getData();
|
|
|
|
fAttributeCheck.checkAttributes(child, GeneralAttributeCheck::E_Appinfo, this);
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_DOCUMENTATION)) {
|
|
|
|
DOMNode* textContent = child->getFirstChild();
|
|
if (textContent && textContent->getNodeType() == DOMNode::TEXT_NODE)
|
|
contents = ((DOMText*) textContent)->getData();
|
|
|
|
fAttributeCheck.checkAttributes(child, GeneralAttributeCheck::E_Documentation, this);
|
|
}
|
|
else {
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::InvalidAnnotationContent);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If the Annotation has no children, get the text directly
|
|
DOMNode* textContent = annotationElem->getFirstChild();
|
|
if (textContent && textContent->getNodeType() == DOMNode::TEXT_NODE)
|
|
contents = ((DOMText*) textContent)->getData();
|
|
}
|
|
|
|
if (contents && !fScanner->getIgnoreAnnotations())
|
|
{
|
|
XSAnnotation* theAnnotation = 0;
|
|
|
|
XMLSize_t nonXSAttSize = nonXSAttList->size();
|
|
|
|
if (nonXSAttSize)
|
|
{
|
|
int annotTokenStart = XMLString::patternMatch(
|
|
contents, SchemaSymbols::fgELT_ANNOTATION);
|
|
|
|
if (annotTokenStart == -1) // something is wrong
|
|
return 0;
|
|
|
|
// set annotation element
|
|
fBuffer.set(contents, annotTokenStart + 10);
|
|
|
|
for (XMLSize_t i=0; i<nonXSAttSize; i++)
|
|
{
|
|
DOMNode* attNode = nonXSAttList->elementAt(i);
|
|
|
|
if (!XMLString::equals(
|
|
annotationElem->getAttributeNS(
|
|
attNode->getNamespaceURI(), attNode->getLocalName())
|
|
, XMLUni::fgZeroLenString)
|
|
)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
fBuffer.append(chSpace);
|
|
fBuffer.append(attNode->getNodeName());
|
|
fBuffer.append(chEqual);
|
|
fBuffer.append(chDoubleQuote);
|
|
processAttValue(attNode->getNodeValue(), fBuffer);
|
|
fBuffer.append(chDoubleQuote);
|
|
}
|
|
|
|
// add remaining annotation content
|
|
fBuffer.append(contents + annotTokenStart + 10);
|
|
|
|
theAnnotation = new (fGrammarPoolMemoryManager) XSAnnotation(fBuffer.getRawBuffer(), fGrammarPoolMemoryManager);
|
|
}
|
|
else
|
|
{
|
|
theAnnotation = new (fGrammarPoolMemoryManager) XSAnnotation(contents, fGrammarPoolMemoryManager);
|
|
}
|
|
|
|
/***
|
|
* set line, col and systemId info
|
|
***/
|
|
theAnnotation->setLineCol(
|
|
((XSDElementNSImpl*)annotationElem)->getLineNo()
|
|
, ((XSDElementNSImpl*)annotationElem)->getColumnNo()
|
|
);
|
|
theAnnotation->setSystemId(fSchemaInfo->getCurrentSchemaURL());
|
|
|
|
return theAnnotation;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Traverse include
|
|
*
|
|
* <include
|
|
* id = ID
|
|
* schemaLocation = anyURI
|
|
* {any attributes with non-schema namespace . . .}>
|
|
* Content: (annotation?)
|
|
* </include>
|
|
*/
|
|
void TraverseSchema::preprocessInclude(const DOMElement* const elem) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
elem, GeneralAttributeCheck::E_Include, this, true, fNonXSAttList);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// First, handle any ANNOTATION declaration
|
|
// -----------------------------------------------------------------------
|
|
if (checkContent(elem, XUtil::getFirstChildElement(elem), true) != 0)
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected);
|
|
|
|
if (fAnnotation)
|
|
fSchemaGrammar->addAnnotation(fAnnotation);
|
|
else if (fScanner->getGenerateSyntheticAnnotations() && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
fSchemaGrammar->addAnnotation(fAnnotation);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Get 'schemaLocation' attribute
|
|
// -----------------------------------------------------------------------
|
|
const XMLCh* schemaLocation = getElementAttValue(elem, SchemaSymbols::fgATT_SCHEMALOCATION, DatatypeValidator::AnyURI);
|
|
|
|
if (!schemaLocation || !*schemaLocation) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNoSchemaLocation, SchemaSymbols::fgELT_INCLUDE);
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Resolve schema location
|
|
// ------------------------------------------------------------------
|
|
fLocator->setValues(fSchemaInfo->getCurrentSchemaURL(), 0,
|
|
((XSDElementNSImpl*) elem)->getLineNo(),
|
|
((XSDElementNSImpl*) elem)->getColumnNo());
|
|
InputSource* srcToFill = resolveSchemaLocation(schemaLocation,
|
|
XMLResourceIdentifier::SchemaInclude);
|
|
Janitor<InputSource> janSrc(srcToFill);
|
|
|
|
// Nothing to do
|
|
if (!srcToFill) {
|
|
return;
|
|
}
|
|
|
|
const XMLCh* includeURL = srcToFill->getSystemId();
|
|
SchemaInfo* includeSchemaInfo = fCachedSchemaInfoList->get(includeURL, fTargetNSURI);
|
|
|
|
if (!includeSchemaInfo && fSchemaInfoList != fCachedSchemaInfoList)
|
|
includeSchemaInfo = fSchemaInfoList->get(includeURL, fTargetNSURI);
|
|
|
|
if (includeSchemaInfo) {
|
|
|
|
fSchemaInfo->addSchemaInfo(includeSchemaInfo, SchemaInfo::INCLUDE);
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Parse input source
|
|
// ------------------------------------------------------------------
|
|
if (!fParser)
|
|
fParser = new (fGrammarPoolMemoryManager) XSDDOMParser(0, fGrammarPoolMemoryManager, 0);
|
|
|
|
fParser->setValidationScheme(XercesDOMParser::Val_Never);
|
|
fParser->setDoNamespaces(true);
|
|
fParser->setUserEntityHandler(fEntityHandler);
|
|
fParser->setUserErrorReporter(fErrorReporter);
|
|
|
|
// Should just issue warning if the schema is not found
|
|
bool flag = srcToFill->getIssueFatalErrorIfNotFound();
|
|
srcToFill->setIssueFatalErrorIfNotFound(false);
|
|
|
|
fParser->parse(*srcToFill);
|
|
|
|
// Reset the InputSource
|
|
srcToFill->setIssueFatalErrorIfNotFound(flag);
|
|
|
|
if (fParser->getSawFatal() && fScanner->getExitOnFirstFatal())
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::SchemaScanFatalError);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Get root element
|
|
// ------------------------------------------------------------------
|
|
DOMDocument* document = fParser->getDocument();
|
|
|
|
if (document) {
|
|
|
|
DOMElement* root = document->getDocumentElement();
|
|
|
|
if (root) {
|
|
|
|
const XMLCh* targetNSURIString = root->getAttribute(SchemaSymbols::fgATT_TARGETNAMESPACE);
|
|
|
|
// check to see if targetNameSpace is right
|
|
if (*targetNSURIString
|
|
&& !XMLString::equals(targetNSURIString,fTargetNSURIString)){
|
|
reportSchemaError(root, XMLUni::fgXMLErrDomain, XMLErrs::IncludeNamespaceDifference,
|
|
schemaLocation, targetNSURIString);
|
|
return;
|
|
}
|
|
|
|
// if targetNamespace is empty, change it to includ'g schema
|
|
// targetNamespace
|
|
if (!*targetNSURIString && root->getAttributeNode(XMLUni::fgXMLNSString) == 0
|
|
&& fTargetNSURI != fEmptyNamespaceURI) {
|
|
root->setAttribute(XMLUni::fgXMLNSString, fTargetNSURIString);
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Update schema information with included schema
|
|
// --------------------------------------------------------
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
|
|
fSchemaInfo = new (fMemoryManager) SchemaInfo(0, 0, 0, fTargetNSURI,
|
|
0,
|
|
includeURL,
|
|
fTargetNSURIString, root,
|
|
fScanner,
|
|
fGrammarPoolMemoryManager);
|
|
|
|
fSchemaInfo->getNamespaceScope()->reset(fEmptyNamespaceURI);
|
|
// Add mapping for the xml prefix
|
|
fSchemaInfo->getNamespaceScope()->addPrefix(XMLUni::fgXMLString, fURIStringPool->addOrFind(XMLUni::fgXMLURIName));
|
|
|
|
fSchemaInfoList->put((void*) fSchemaInfo->getCurrentSchemaURL(),
|
|
fSchemaInfo->getTargetNSURI(), fSchemaInfo);
|
|
fPreprocessedNodes->put((void*) elem, fSchemaInfo);
|
|
saveInfo->addSchemaInfo(fSchemaInfo, SchemaInfo::INCLUDE);
|
|
traverseSchemaHeader(root);
|
|
preprocessChildren(root);
|
|
fSchemaInfo = saveInfo;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void TraverseSchema::traverseInclude(const DOMElement* const elem) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
SchemaInfo* includeInfo = fPreprocessedNodes->get(elem);
|
|
|
|
if (includeInfo) {
|
|
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
|
|
fSchemaInfo = includeInfo;
|
|
processChildren(includeInfo->getRoot());
|
|
fSchemaInfo = saveInfo;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Traverse import
|
|
*
|
|
* <import
|
|
* id = ID
|
|
* namespace = anyURI
|
|
* schemaLocation = anyURI
|
|
* {any attributes with non-schema namespace . . .}>
|
|
* Content: (annotation?)
|
|
* </import>
|
|
*/
|
|
void TraverseSchema::preprocessImport(const DOMElement* const elem) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
elem, GeneralAttributeCheck::E_Import, this, true, fNonXSAttList);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// First, handle any ANNOTATION declaration
|
|
// -----------------------------------------------------------------------
|
|
if (checkContent(elem, XUtil::getFirstChildElement(elem), true) != 0)
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected);
|
|
|
|
if (fAnnotation)
|
|
fSchemaGrammar->addAnnotation(fAnnotation);
|
|
else if (fScanner->getGenerateSyntheticAnnotations() && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
fSchemaGrammar->addAnnotation(fAnnotation);
|
|
}
|
|
// -----------------------------------------------------------------------
|
|
// Handle 'namespace' attribute
|
|
// -----------------------------------------------------------------------
|
|
const XMLCh* nameSpace = getElementAttValue(elem, SchemaSymbols::fgATT_NAMESPACE, DatatypeValidator::AnyURI);
|
|
const XMLCh* nameSpaceValue = nameSpace ? nameSpace : XMLUni::fgZeroLenString;
|
|
|
|
if (XMLString::equals(nameSpaceValue, fTargetNSURIString)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::Import_1_1);
|
|
return;
|
|
}
|
|
|
|
if (!*nameSpaceValue && fTargetNSURI == fEmptyNamespaceURI) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::Import_1_2);
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Get 'schemaLocation' attribute
|
|
// ------------------------------------------------------------------
|
|
const XMLCh* schemaLocation = getElementAttValue(elem, SchemaSymbols::fgATT_SCHEMALOCATION, DatatypeValidator::AnyURI);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Resolve namespace to a grammar
|
|
// ------------------------------------------------------------------
|
|
Grammar* aGrammar = 0;
|
|
|
|
{
|
|
XMLSchemaDescription* gramDesc =fGrammarResolver->getGrammarPool()->createSchemaDescription(nameSpaceValue);
|
|
Janitor<XMLSchemaDescription> janName(gramDesc);
|
|
gramDesc->setContextType(XMLSchemaDescription::CONTEXT_IMPORT);
|
|
gramDesc->setLocationHints(schemaLocation);
|
|
aGrammar = fGrammarResolver->getGrammar(gramDesc);
|
|
}
|
|
|
|
bool grammarFound = (aGrammar && (aGrammar->getGrammarType() == Grammar::SchemaGrammarType));
|
|
|
|
if (grammarFound) {
|
|
addImportedNS(fURIStringPool->addOrFind(nameSpaceValue));
|
|
}
|
|
|
|
// a bare <xs:import/> doesn't load anything
|
|
if(!schemaLocation && !nameSpace)
|
|
return;
|
|
|
|
// ------------------------------------------------------------------
|
|
// Resolve schema location
|
|
// ------------------------------------------------------------------
|
|
fLocator->setValues(fSchemaInfo->getCurrentSchemaURL(), 0,
|
|
((XSDElementNSImpl*) elem)->getLineNo(),
|
|
((XSDElementNSImpl*) elem)->getColumnNo());
|
|
InputSource* srcToFill = resolveSchemaLocation(schemaLocation,
|
|
XMLResourceIdentifier::SchemaImport, nameSpace);
|
|
|
|
// Nothing to do
|
|
if (!srcToFill) {
|
|
if (!grammarFound) {
|
|
addImportedNS(fURIStringPool->addOrFind(nameSpaceValue));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
Janitor<InputSource> janSrc(srcToFill);
|
|
const XMLCh* importURL = srcToFill->getSystemId();
|
|
unsigned int nameSpaceId = nameSpace ? fURIStringPool->addOrFind(nameSpace) : fEmptyNamespaceURI;
|
|
|
|
SchemaInfo* importSchemaInfo = fCachedSchemaInfoList->get(importURL, nameSpaceId);
|
|
|
|
if (!importSchemaInfo && fSchemaInfoList != fCachedSchemaInfoList)
|
|
importSchemaInfo = fSchemaInfoList->get(importURL, nameSpaceId);
|
|
|
|
if (importSchemaInfo) {
|
|
fSchemaInfo->addSchemaInfo(importSchemaInfo, SchemaInfo::IMPORT);
|
|
addImportedNS(importSchemaInfo->getTargetNSURI());
|
|
return;
|
|
}
|
|
|
|
if (grammarFound) {
|
|
if (!fScanner->getHandleMultipleImports())
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Parse input source
|
|
// ------------------------------------------------------------------
|
|
if (!fParser)
|
|
fParser = new (fGrammarPoolMemoryManager) XSDDOMParser(0, fGrammarPoolMemoryManager, 0);
|
|
|
|
fParser->setValidationScheme(XercesDOMParser::Val_Never);
|
|
fParser->setDoNamespaces(true);
|
|
fParser->setUserEntityHandler(fEntityHandler);
|
|
fParser->setUserErrorReporter(fErrorReporter);
|
|
|
|
// Should just issue warning if the schema is not found
|
|
bool flag = srcToFill->getIssueFatalErrorIfNotFound();
|
|
srcToFill->setIssueFatalErrorIfNotFound(false);
|
|
|
|
fParser->parse(*srcToFill) ;
|
|
|
|
// Reset the InputSource
|
|
srcToFill->setIssueFatalErrorIfNotFound(flag);
|
|
|
|
if (fParser->getSawFatal() && fScanner->getExitOnFirstFatal())
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::SchemaScanFatalError);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Get root element
|
|
// ------------------------------------------------------------------
|
|
DOMDocument* document = fParser->getDocument();
|
|
|
|
if (document) {
|
|
|
|
DOMElement* root = document->getDocumentElement();
|
|
|
|
if (!root) {
|
|
return;
|
|
}
|
|
|
|
const XMLCh* targetNSURIString = root->getAttribute(SchemaSymbols::fgATT_TARGETNAMESPACE);
|
|
|
|
if (!XMLString::equals(targetNSURIString, nameSpaceValue)) {
|
|
reportSchemaError(root, XMLUni::fgXMLErrDomain, XMLErrs::ImportNamespaceDifference,
|
|
schemaLocation, targetNSURIString, nameSpaceValue);
|
|
}
|
|
else {
|
|
|
|
// --------------------------------------------------------
|
|
// Preprocess new schema
|
|
// --------------------------------------------------------
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
fSchemaGrammar->setScopeCount (fScopeCount);
|
|
fSchemaGrammar->setAnonTypeCount (fAnonXSTypeCount);
|
|
if (grammarFound) {
|
|
fSchemaGrammar = (SchemaGrammar*) aGrammar;
|
|
}
|
|
else {
|
|
fSchemaGrammar = new (fGrammarPoolMemoryManager) SchemaGrammar(fGrammarPoolMemoryManager);
|
|
}
|
|
fScopeCount = fSchemaGrammar->getScopeCount ();
|
|
fAnonXSTypeCount = fSchemaGrammar->getAnonTypeCount ();
|
|
|
|
XMLSchemaDescription* gramDesc = (XMLSchemaDescription*) fSchemaGrammar->getGrammarDescription();
|
|
gramDesc->setContextType(XMLSchemaDescription::CONTEXT_IMPORT);
|
|
gramDesc->setLocationHints(importURL);
|
|
|
|
preprocessSchema(root, importURL, grammarFound);
|
|
fPreprocessedNodes->put((void*) elem, fSchemaInfo);
|
|
|
|
// --------------------------------------------------------
|
|
// Restore old schema information
|
|
// --------------------------------------------------------
|
|
restoreSchemaInfo(saveInfo, SchemaInfo::IMPORT);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void TraverseSchema::traverseImport(const DOMElement* const elem) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
SchemaInfo* importInfo = fPreprocessedNodes->get(elem);
|
|
|
|
if (importInfo) {
|
|
|
|
// --------------------------------------------------------
|
|
// Traverse new schema
|
|
// --------------------------------------------------------
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
|
|
restoreSchemaInfo(importInfo, SchemaInfo::IMPORT);
|
|
doTraverseSchema(importInfo->getRoot());
|
|
|
|
// --------------------------------------------------------
|
|
// Restore old schema information
|
|
// --------------------------------------------------------
|
|
restoreSchemaInfo(saveInfo, SchemaInfo::IMPORT);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Traverse redefine declaration
|
|
*
|
|
* <redefine>
|
|
* schemaLocation = uriReference
|
|
* {any attributes with non-schema namespace . . .}>
|
|
* Content: (annotation | (
|
|
* attributeGroup | complexType | group | simpleType))*
|
|
* </redefine>
|
|
*/
|
|
void TraverseSchema::preprocessRedefine(const DOMElement* const redefineElem) {
|
|
|
|
NamespaceScopeManager nsMgr(redefineElem, fSchemaInfo, this);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
redefineElem, GeneralAttributeCheck::E_Redefine, this, true
|
|
);
|
|
|
|
// First, we look through the children of redefineElem. Each one will
|
|
// correspond to an element of the redefined schema that we need to
|
|
// redefine. To do this, we rename the element of the redefined schema,
|
|
// and rework the base or ref tag of the kid we're working on to refer to
|
|
// the renamed group or derive the renamed type. Once we've done this, we
|
|
// actually go through the schema being redefined and convert it to a
|
|
// grammar. Only then do we run through redefineDecl's kids and put them
|
|
// in the grammar.
|
|
SchemaInfo* redefiningInfo = fSchemaInfo;
|
|
|
|
if (!openRedefinedSchema(redefineElem)) {
|
|
|
|
redefiningInfo->addFailedRedefine(redefineElem);
|
|
return;
|
|
}
|
|
|
|
if (!fRedefineComponents) {
|
|
fRedefineComponents = new (fMemoryManager) RefHash2KeysTableOf<XMLCh>(13, (bool) false, fMemoryManager);
|
|
}
|
|
|
|
SchemaInfo* redefinedInfo = fSchemaInfo;
|
|
renameRedefinedComponents(redefineElem, redefiningInfo, redefinedInfo);
|
|
|
|
// Now we have to preprocess our nicely-renamed schemas.
|
|
if (fPreprocessedNodes->containsKey(redefineElem)) {
|
|
|
|
fSchemaInfo = redefinedInfo;
|
|
preprocessChildren(fSchemaInfo->getRoot());
|
|
}
|
|
|
|
fSchemaInfo = redefiningInfo;
|
|
}
|
|
|
|
void TraverseSchema::traverseRedefine(const DOMElement* const redefineElem) {
|
|
|
|
NamespaceScopeManager nsMgr(redefineElem, fSchemaInfo, this);
|
|
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
SchemaInfo* redefinedInfo = fPreprocessedNodes->get(redefineElem);
|
|
|
|
if (redefinedInfo) {
|
|
|
|
// Now we have to march through our nicely-renamed schemas. When
|
|
// we do these traversals other <redefine>'s may perhaps be
|
|
// encountered; we leave recursion to sort this out.
|
|
fSchemaInfo = redefinedInfo;
|
|
processChildren(fSchemaInfo->getRoot());
|
|
fSchemaInfo = saveInfo;
|
|
|
|
// Now traverse our own <redefine>
|
|
processChildren(redefineElem);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Traverse the Choice, Sequence declaration
|
|
*
|
|
* <choice-sequence
|
|
* id = ID
|
|
* maxOccurs = (nonNegativeInteger | unbounded) : 1
|
|
* minOccurs = nonNegativeInteger : 1
|
|
* Content: (annotation?, (element | group | choice | sequence | any)*)
|
|
* </choice-sequence>
|
|
*/
|
|
ContentSpecNode*
|
|
TraverseSchema::traverseChoiceSequence(const DOMElement* const elem,
|
|
const int modelGroupType,
|
|
bool& hasChildren)
|
|
{
|
|
hasChildren = false;
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
elem, GeneralAttributeCheck::E_Sequence, this, false, fNonXSAttList
|
|
);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Process contents
|
|
// -----------------------------------------------------------------------
|
|
DOMElement* child = checkContent(elem, XUtil::getFirstChildElement(elem), true);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
}
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
Janitor<ContentSpecNode> left(0);
|
|
Janitor<ContentSpecNode> right(0);
|
|
|
|
bool hadContent = false;
|
|
|
|
Janitor<ContentSpecNode> contentSpecNode(0);
|
|
for (; child != 0; child = XUtil::getNextSiblingElement(child)) {
|
|
hasChildren = true;
|
|
contentSpecNode.release();
|
|
bool seeParticle = false;
|
|
bool wasAny = false;
|
|
const XMLCh* childName = child->getLocalName();
|
|
|
|
if (XMLString::equals(childName, SchemaSymbols::fgELT_ELEMENT)) {
|
|
|
|
SchemaElementDecl* elemDecl = traverseElementDecl(child);
|
|
|
|
if (!elemDecl )
|
|
continue;
|
|
|
|
contentSpecNode.reset(new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
elemDecl
|
|
, fGrammarPoolMemoryManager
|
|
));
|
|
seeParticle = true;
|
|
}
|
|
else if (XMLString::equals(childName, SchemaSymbols::fgELT_GROUP)) {
|
|
|
|
XercesGroupInfo* grpInfo = traverseGroupDecl(child, false);
|
|
|
|
if (!grpInfo) {
|
|
continue;
|
|
}
|
|
|
|
ContentSpecNode* grpContentSpecNode = grpInfo->getContentSpec();
|
|
|
|
if (!grpContentSpecNode) {
|
|
continue;
|
|
}
|
|
|
|
if (grpContentSpecNode->hasAllContent()) {
|
|
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::AllContentLimited);
|
|
continue;
|
|
}
|
|
|
|
contentSpecNode.reset(new (fGrammarPoolMemoryManager) ContentSpecNode(*grpContentSpecNode));
|
|
seeParticle = true;
|
|
}
|
|
else if (XMLString::equals(childName, SchemaSymbols::fgELT_CHOICE)) {
|
|
bool hasChild;
|
|
contentSpecNode.reset(traverseChoiceSequence(child,ContentSpecNode::Choice, hasChild));
|
|
seeParticle = true;
|
|
}
|
|
else if (XMLString::equals(childName, SchemaSymbols::fgELT_SEQUENCE)) {
|
|
bool hasChild;
|
|
contentSpecNode.reset(traverseChoiceSequence(child,ContentSpecNode::Sequence, hasChild));
|
|
seeParticle = true;
|
|
}
|
|
else if (XMLString::equals(childName, SchemaSymbols::fgELT_ANY)) {
|
|
|
|
contentSpecNode.reset(traverseAny(child));
|
|
seeParticle = true;
|
|
wasAny = true;
|
|
}
|
|
else {
|
|
reportSchemaError(child, XMLUni::fgValidityDomain, XMLValid::GroupContentRestricted,
|
|
childName,
|
|
((ContentSpecNode::NodeTypes) modelGroupType) == ContentSpecNode::Choice?SchemaSymbols::fgELT_CHOICE:SchemaSymbols::fgELT_SEQUENCE);
|
|
}
|
|
|
|
if (seeParticle) {
|
|
checkMinMax(contentSpecNode.get(), child, Not_All_Context);
|
|
if (wasAny && contentSpecNode.get()->getMaxOccurs() == 0) {
|
|
contentSpecNode.reset(0);
|
|
}
|
|
}
|
|
|
|
if (contentSpecNode.get()) {
|
|
hadContent = true;
|
|
}
|
|
|
|
if (left.get() == 0) {
|
|
left.reset(contentSpecNode.release());
|
|
}
|
|
else if (right.get() == 0) {
|
|
right.reset(contentSpecNode.release());
|
|
}
|
|
else {
|
|
ContentSpecNode* newNode =
|
|
new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
(ContentSpecNode::NodeTypes) modelGroupType
|
|
, left.get()
|
|
, right.get()
|
|
, true
|
|
, true
|
|
, fGrammarPoolMemoryManager
|
|
);
|
|
|
|
left.release();
|
|
right.release();
|
|
|
|
left.reset(newNode);
|
|
right.reset(contentSpecNode.release());
|
|
}
|
|
}
|
|
contentSpecNode.release();
|
|
|
|
if (hadContent)
|
|
{
|
|
ContentSpecNode* newNode =
|
|
new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
((ContentSpecNode::NodeTypes) modelGroupType) == ContentSpecNode::Choice
|
|
? ContentSpecNode::ModelGroupChoice : ContentSpecNode::ModelGroupSequence
|
|
, left.get()
|
|
, right.get()
|
|
, true
|
|
, true
|
|
, fGrammarPoolMemoryManager
|
|
);
|
|
|
|
left.release();
|
|
|
|
left.reset(newNode);
|
|
|
|
if (!janAnnot.isDataNull())
|
|
fSchemaGrammar->putAnnotation(left.get(), janAnnot.release());
|
|
}
|
|
|
|
right.release();
|
|
return left.release();
|
|
}
|
|
|
|
/**
|
|
* Traverse SimpleType declaration:
|
|
* <simpleType
|
|
* id = ID
|
|
* name = NCName>
|
|
* Content: (annotation? , ((list | restriction | union)))
|
|
* </simpleType>
|
|
*
|
|
* traverse <list>|<restriction>|<union>
|
|
*/
|
|
DatatypeValidator*
|
|
TraverseSchema::traverseSimpleTypeDecl(const DOMElement* const childElem,
|
|
const bool topLevel, int baseRefContext)
|
|
{
|
|
NamespaceScopeManager nsMgr(childElem, fSchemaInfo, this);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Process contents
|
|
// ------------------------------------------------------------------
|
|
const XMLCh* name = getElementAttValue(childElem,SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
bool nameEmpty = (!name || !*name);
|
|
|
|
if (topLevel && nameEmpty) {
|
|
reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameGlobalElement,
|
|
SchemaSymbols::fgELT_SIMPLETYPE);
|
|
return 0;
|
|
}
|
|
else if(!topLevel && !nameEmpty) {
|
|
reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::AttributeDisallowedLocal,
|
|
SchemaSymbols::fgATT_NAME, childElem->getLocalName());
|
|
return 0;
|
|
}
|
|
|
|
if (nameEmpty) { // anonymous simpleType
|
|
name = genAnonTypeName(fgAnonSNamePrefix);
|
|
}
|
|
else if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name)) ) {
|
|
|
|
reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName,
|
|
SchemaSymbols::fgELT_SIMPLETYPE, name);
|
|
return 0;
|
|
}
|
|
|
|
fBuffer.set(fTargetNSURIString);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(name);
|
|
|
|
unsigned int fullTypeNameId = fStringPool->addOrFind(fBuffer.getRawBuffer());
|
|
const XMLCh* fullName = fStringPool->getValueForId(fullTypeNameId);
|
|
|
|
//check if we have already traversed the same simpleType decl
|
|
DatatypeValidator* dv = fDatatypeRegistry->getDatatypeValidator(fullName);
|
|
|
|
if (!dv) {
|
|
|
|
// -------------------------------------------------------------------
|
|
// Check attributes
|
|
// -------------------------------------------------------------------
|
|
unsigned short scope = (topLevel) ? GeneralAttributeCheck::E_SimpleTypeGlobal
|
|
: GeneralAttributeCheck::E_SimpleTypeLocal;
|
|
|
|
fAttributeCheck.checkAttributes(
|
|
childElem, scope, this, topLevel, fNonXSAttList
|
|
);
|
|
|
|
// Circular constraint checking
|
|
if (fCurrentTypeNameStack->containsElement(fullTypeNameId)) {
|
|
|
|
reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::NoCircularDefinition, name);
|
|
return 0;
|
|
}
|
|
|
|
fCurrentTypeNameStack->addElement(fullTypeNameId);
|
|
|
|
// Get 'final' values
|
|
int finalSet = parseFinalSet(childElem, S_Final);
|
|
|
|
// annotation?,(list|restriction|union)
|
|
DOMElement* content= checkContent(
|
|
childElem, XUtil::getFirstChildElement(childElem), false);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(childElem, fNonXSAttList);
|
|
}
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
if (content == 0) {
|
|
|
|
reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::EmptySimpleTypeContent);
|
|
popCurrentTypeNameStack();
|
|
return 0;
|
|
}
|
|
|
|
const XMLCh* varietyName = content->getLocalName();
|
|
|
|
// Remark: some code will be repeated in list|restriction| union but it
|
|
// is cleaner that way
|
|
if (XMLString::equals(varietyName, SchemaSymbols::fgELT_LIST)) { //traverse List
|
|
if ((baseRefContext & SchemaSymbols::XSD_LIST) != 0) {
|
|
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::AtomicItemType);
|
|
popCurrentTypeNameStack();
|
|
return 0;
|
|
}
|
|
|
|
dv = traverseByList(childElem, content, name, fullName, finalSet, &janAnnot);
|
|
}
|
|
else if (XMLString::equals(varietyName, SchemaSymbols::fgELT_RESTRICTION)) { //traverse Restriction
|
|
dv = traverseByRestriction(childElem, content, name, fullName, finalSet, &janAnnot);
|
|
}
|
|
else if (XMLString::equals(varietyName, SchemaSymbols::fgELT_UNION)) { //traverse union
|
|
dv = traverseByUnion(childElem, content, name, fullName, finalSet, baseRefContext, &janAnnot);
|
|
}
|
|
else {
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::FeatureUnsupported, varietyName);
|
|
popCurrentTypeNameStack();
|
|
}
|
|
|
|
if (dv) {
|
|
if (nameEmpty)
|
|
dv->setAnonymous();
|
|
|
|
if (!janAnnot.isDataNull())
|
|
fSchemaGrammar->putAnnotation(dv, janAnnot.release());
|
|
}
|
|
}
|
|
|
|
return dv;
|
|
}
|
|
|
|
/**
|
|
* Traverse ComplexType Declaration - CR Implementation.
|
|
*
|
|
* <complexType
|
|
* abstract = boolean
|
|
* block = #all or (possibly empty) subset of {extension, restriction}
|
|
* final = #all or (possibly empty) subset of {extension, restriction}
|
|
* id = ID
|
|
* mixed = boolean : false
|
|
* name = NCName>
|
|
* Content: (annotation? , (simpleContent | complexContent |
|
|
* ( (group | all | choice | sequence)? ,
|
|
* ( (attribute | attributeGroup)* , anyAttribute?))))
|
|
* </complexType>
|
|
*/
|
|
int TraverseSchema::traverseComplexTypeDecl(const DOMElement* const elem,
|
|
const bool topLevel,
|
|
const XMLCh* const recursingTypeName) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
// Get the attributes of the complexType
|
|
const XMLCh* name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
bool isAnonymous = false;
|
|
|
|
if (!name || !*name) {
|
|
|
|
if (topLevel) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TopLevelNoNameComplexType);
|
|
return -1;
|
|
}
|
|
|
|
if (recursingTypeName)
|
|
name = recursingTypeName;
|
|
else {
|
|
name = genAnonTypeName(fgAnonCNamePrefix);
|
|
isAnonymous = true;
|
|
}
|
|
}
|
|
|
|
if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name)) ) {
|
|
|
|
//REVISIT - Should we return or continue and save type with wrong name?
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName,
|
|
SchemaSymbols::fgELT_COMPLEXTYPE, name);
|
|
return -1;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Check if the type has already been registered
|
|
// ------------------------------------------------------------------
|
|
fBuffer.set(fTargetNSURIString);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(name);
|
|
|
|
int typeNameIndex = fStringPool->addOrFind(fBuffer.getRawBuffer());
|
|
const XMLCh* fullName = fStringPool->getValueForId(typeNameIndex);
|
|
ComplexTypeInfo* typeInfo = 0;
|
|
|
|
if (topLevel || recursingTypeName) {
|
|
|
|
typeInfo = fComplexTypeRegistry->get(fullName);
|
|
|
|
if (typeInfo && !typeInfo->getPreprocessed()) {
|
|
return typeNameIndex;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check Attributes
|
|
// -----------------------------------------------------------------------
|
|
bool preProcessFlag = (typeInfo) ? typeInfo->getPreprocessed() : false;
|
|
if (!preProcessFlag) {
|
|
fAttributeCheck.checkAttributes(
|
|
elem, (topLevel) ? GeneralAttributeCheck::E_ComplexTypeGlobal
|
|
: GeneralAttributeCheck::E_ComplexTypeLocal
|
|
, this, topLevel, fNonXSAttList
|
|
);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Create a new instance
|
|
// -----------------------------------------------------------------------
|
|
XMLSize_t previousCircularCheckIndex = fCircularCheckIndex;
|
|
unsigned int previousScope = fCurrentScope;
|
|
|
|
if (preProcessFlag) {
|
|
|
|
fCurrentScope = typeInfo->getScopeDefined();
|
|
typeInfo->setPreprocessed(false);
|
|
}
|
|
else {
|
|
|
|
// ------------------------------------------------------------------
|
|
// Register the type
|
|
// ------------------------------------------------------------------
|
|
typeInfo = new (fGrammarPoolMemoryManager) ComplexTypeInfo(fGrammarPoolMemoryManager);
|
|
if(isAnonymous) {
|
|
typeInfo->setAnonymous();
|
|
}
|
|
|
|
fCurrentScope = fScopeCount++;
|
|
fComplexTypeRegistry->put((void*) fullName, typeInfo);
|
|
typeInfo->setTypeName(fullName);
|
|
typeInfo->setScopeDefined(fCurrentScope);
|
|
|
|
if (fFullConstraintChecking) {
|
|
|
|
XSDLocator* aLocator = new (fGrammarPoolMemoryManager) XSDLocator();
|
|
aLocator->setValues(fStringPool->getValueForId(fStringPool->addOrFind(fSchemaInfo->getCurrentSchemaURL())),
|
|
0, ((XSDElementNSImpl*) elem)->getLineNo(),
|
|
((XSDElementNSImpl*) elem)->getColumnNo());
|
|
typeInfo->setLocator(aLocator);
|
|
}
|
|
}
|
|
|
|
fCurrentTypeNameStack->addElement(typeNameIndex);
|
|
ComplexTypeInfo* saveTypeInfo = fCurrentComplexType;
|
|
fCurrentComplexType = typeInfo;
|
|
|
|
// ------------------------------------------------------------------
|
|
// First, handle any ANNOTATION declaration and get next child
|
|
// ------------------------------------------------------------------
|
|
DOMElement* child = checkContent(elem, XUtil::getFirstChildElement(elem), true, !preProcessFlag);
|
|
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
}
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Process the content of the complex type declaration
|
|
// ------------------------------------------------------------------
|
|
try {
|
|
|
|
const XMLCh* mixedVal = getElementAttValue(elem,SchemaSymbols::fgATT_MIXED, DatatypeValidator::Boolean);
|
|
bool isMixed = false;
|
|
|
|
if ((mixedVal && *mixedVal)
|
|
&& (XMLString::equals(SchemaSymbols::fgATTVAL_TRUE, mixedVal)
|
|
|| XMLString::equals(fgValueOne, mixedVal))) {
|
|
isMixed = true;
|
|
}
|
|
|
|
if (child == 0) {
|
|
// EMPTY complexType with complexContent
|
|
processComplexContent(elem, name, child, typeInfo, 0, isMixed);
|
|
}
|
|
else {
|
|
|
|
const XMLCh* childName = child->getLocalName();
|
|
|
|
if (XMLString::equals(childName, SchemaSymbols::fgELT_SIMPLECONTENT)) {
|
|
|
|
// SIMPLE CONTENT element
|
|
traverseSimpleContentDecl(name, fullName, child, typeInfo, &janAnnot);
|
|
|
|
if (XUtil::getNextSiblingElement(child) != 0) {
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildFollowingSimpleContent);
|
|
}
|
|
}
|
|
else if (XMLString::equals(childName, SchemaSymbols::fgELT_COMPLEXCONTENT)) {
|
|
|
|
// COMPLEX CONTENT element
|
|
traverseComplexContentDecl(name, child, typeInfo, isMixed, &janAnnot);
|
|
|
|
if (XUtil::getNextSiblingElement(child) != 0) {
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildFollowingConplexContent);
|
|
}
|
|
}
|
|
else if (fCurrentGroupInfo) {
|
|
typeInfo->setPreprocessed(true);
|
|
}
|
|
else {
|
|
// We must have ....
|
|
// GROUP, ALL, SEQUENCE or CHOICE, followed by optional attributes
|
|
// Note that it's possible that only attributes are specified.
|
|
processComplexContent(elem, name, child, typeInfo, 0, isMixed);
|
|
}
|
|
}
|
|
}
|
|
catch(const TraverseSchema::ExceptionCodes aCode) {
|
|
if (aCode == TraverseSchema::InvalidComplexTypeInfo)
|
|
defaultComplexTypeInfo(typeInfo);
|
|
else if (aCode == TraverseSchema::RecursingElement)
|
|
typeInfo->setPreprocessed();
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Finish the setup of the typeInfo
|
|
// ------------------------------------------------------------------
|
|
if (!preProcessFlag) {
|
|
|
|
const XMLCh* abstractAttVal = getElementAttValue(elem, SchemaSymbols::fgATT_ABSTRACT, DatatypeValidator::Boolean);
|
|
int blockSet = parseBlockSet(elem, C_Block);
|
|
int finalSet = parseFinalSet(elem, EC_Final);
|
|
|
|
typeInfo->setBlockSet(blockSet);
|
|
typeInfo->setFinalSet(finalSet);
|
|
|
|
if ((abstractAttVal && *abstractAttVal)
|
|
&& (XMLString::equals(abstractAttVal, SchemaSymbols::fgATTVAL_TRUE)
|
|
|| XMLString::equals(abstractAttVal, fgValueOne))) {
|
|
typeInfo->setAbstract(true);
|
|
}
|
|
else {
|
|
typeInfo->setAbstract(false);
|
|
}
|
|
}
|
|
|
|
// Store Annotation
|
|
if (!janAnnot.isDataNull())
|
|
fSchemaGrammar->putAnnotation(typeInfo, janAnnot.release());
|
|
|
|
// ------------------------------------------------------------------
|
|
// Before exiting, restore the scope, mainly for nested anonymous types
|
|
// ------------------------------------------------------------------
|
|
popCurrentTypeNameStack();
|
|
fCircularCheckIndex = previousCircularCheckIndex;
|
|
fCurrentScope = previousScope;
|
|
fCurrentComplexType = saveTypeInfo;
|
|
|
|
return typeNameIndex;
|
|
}
|
|
|
|
/**
|
|
* Traverse Group Declaration.
|
|
*
|
|
* <group
|
|
* id = ID
|
|
* maxOccurs = string
|
|
* minOccurs = nonNegativeInteger
|
|
* name = NCName
|
|
* ref = QName>
|
|
* Content: (annotation? , (all | choice | sequence)?)
|
|
* <group/>
|
|
*
|
|
*/
|
|
XercesGroupInfo*
|
|
TraverseSchema::traverseGroupDecl(const DOMElement* const elem,
|
|
const bool topLevel) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
const XMLCh* name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
const XMLCh* ref = getElementAttValue(elem, SchemaSymbols::fgATT_REF, DatatypeValidator::QName);
|
|
bool nameEmpty = (!name || !*name);
|
|
bool refEmpty = (!ref || !*ref);
|
|
|
|
if (nameEmpty && topLevel) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameGlobalElement,
|
|
SchemaSymbols::fgELT_GROUP);
|
|
return 0;
|
|
}
|
|
|
|
if (nameEmpty && refEmpty) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameRefGroup);
|
|
return 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Check attributes
|
|
// ------------------------------------------------------------------
|
|
unsigned short scope = (topLevel) ? GeneralAttributeCheck::E_GroupGlobal
|
|
: GeneralAttributeCheck::E_GroupRef;
|
|
fAttributeCheck.checkAttributes(elem, scope, this, topLevel, fNonXSAttList);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Handle "ref="
|
|
// ------------------------------------------------------------------
|
|
if (!topLevel) {
|
|
|
|
if (refEmpty) {
|
|
return 0;
|
|
}
|
|
|
|
return processGroupRef(elem, ref);
|
|
}
|
|
|
|
// name must be a valid NCName
|
|
if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName,
|
|
SchemaSymbols::fgELT_GROUP, name);
|
|
return 0;
|
|
}
|
|
|
|
fBuffer.set(fTargetNSURIString);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(name);
|
|
|
|
unsigned int nameIndex = fStringPool->addOrFind(fBuffer.getRawBuffer());
|
|
const XMLCh* fullName = fStringPool->getValueForId(nameIndex);
|
|
XercesGroupInfo* groupInfo = fGroupRegistry->get(fullName);
|
|
|
|
if (groupInfo) {
|
|
return groupInfo;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Check for annotations
|
|
// ------------------------------------------------------------------
|
|
DOMElement* content = checkContent(elem, XUtil::getFirstChildElement(elem), true);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
}
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
// ------------------------------------------------------------------
|
|
// Process contents of global groups
|
|
// ------------------------------------------------------------------
|
|
unsigned int saveScope = fCurrentScope;
|
|
Janitor<ContentSpecNode> specNode(0);
|
|
XercesGroupInfo* saveGroupInfo = fCurrentGroupInfo;
|
|
|
|
Janitor<XercesGroupInfo> newGroupInfoJan(new (fGrammarPoolMemoryManager) XercesGroupInfo(
|
|
fStringPool->addOrFind(name), fTargetNSURI, fGrammarPoolMemoryManager));
|
|
fCurrentGroupStack->addElement(nameIndex);
|
|
XercesGroupInfo* const newGroupInfo = newGroupInfoJan.get();
|
|
fCurrentGroupInfo = newGroupInfo;
|
|
|
|
fCurrentScope = fScopeCount++;
|
|
fCurrentGroupInfo->setScope(fCurrentScope);
|
|
|
|
if (content == 0) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::GroupContentError, name);
|
|
}
|
|
else {
|
|
|
|
if (content->getAttributeNode(SchemaSymbols::fgATT_MINOCCURS) != 0
|
|
|| content->getAttributeNode(SchemaSymbols::fgATT_MAXOCCURS) != 0) {
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::MinMaxOnGroupChild);
|
|
}
|
|
|
|
bool illegalChild = false;
|
|
const XMLCh* childName = content->getLocalName();
|
|
bool hasChild;
|
|
|
|
|
|
if (XMLString::equals(childName, SchemaSymbols::fgELT_SEQUENCE)) {
|
|
specNode.reset(traverseChoiceSequence(content, ContentSpecNode::Sequence, hasChild));
|
|
}
|
|
else if (XMLString::equals(childName, SchemaSymbols::fgELT_CHOICE)) {
|
|
specNode.reset(traverseChoiceSequence(content, ContentSpecNode::Choice, hasChild));
|
|
}
|
|
else if (XMLString::equals(childName, SchemaSymbols::fgELT_ALL)) {
|
|
specNode.reset(traverseAll(content, hasChild));
|
|
}
|
|
else {
|
|
illegalChild = true;
|
|
}
|
|
|
|
if (illegalChild || XUtil::getNextSiblingElement(content) != 0) {
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::GroupContentError, name);
|
|
}
|
|
|
|
// copy local elements to complex type if it exists
|
|
if (fCurrentComplexType)
|
|
processElements(elem, fCurrentGroupInfo, fCurrentComplexType);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Set groupInfo and pop group name from stack
|
|
// ------------------------------------------------------------------
|
|
XMLSize_t stackSize = fCurrentGroupStack->size();
|
|
|
|
if (stackSize != 0) {
|
|
fCurrentGroupStack->removeElementAt(stackSize - 1);
|
|
}
|
|
|
|
fCurrentGroupInfo->setContentSpec(specNode.release());
|
|
fGroupRegistry->put((void*) fullName, fCurrentGroupInfo);
|
|
newGroupInfoJan.release();
|
|
fCurrentGroupInfo = saveGroupInfo;
|
|
fCurrentScope = saveScope;
|
|
|
|
// Store Annotation
|
|
if (!janAnnot.isDataNull()) {
|
|
fSchemaGrammar->putAnnotation(newGroupInfo, janAnnot.release());
|
|
}
|
|
|
|
if (fFullConstraintChecking) {
|
|
|
|
XSDLocator* aLocator = new (fGrammarPoolMemoryManager) XSDLocator();
|
|
|
|
newGroupInfo->setLocator(aLocator);
|
|
aLocator->setValues(fStringPool->getValueForId(fStringPool->addOrFind(fSchemaInfo->getCurrentSchemaURL())),
|
|
0, ((XSDElementNSImpl*) elem)->getLineNo(),
|
|
((XSDElementNSImpl*) elem)->getColumnNo());
|
|
|
|
if (fRedefineComponents && fRedefineComponents->get(SchemaSymbols::fgELT_GROUP, nameIndex))
|
|
{
|
|
|
|
fBuffer.set(fullName);
|
|
fBuffer.append(SchemaSymbols::fgRedefIdentifier);
|
|
unsigned int rdfNameIndex = fStringPool->addOrFind(fBuffer.getRawBuffer());
|
|
|
|
if (fCurrentGroupStack->containsElement(rdfNameIndex))
|
|
{
|
|
reportSchemaError(aLocator, XMLUni::fgXMLErrDomain, XMLErrs::NoCircularDefinition, name);
|
|
}
|
|
else
|
|
{
|
|
XercesGroupInfo* baseGroup = fGroupRegistry->get(fBuffer.getRawBuffer());
|
|
if (baseGroup)
|
|
{
|
|
newGroupInfo->setBaseGroup(baseGroup);
|
|
}
|
|
else
|
|
{
|
|
fBuffer.set(name);
|
|
fBuffer.append(SchemaSymbols::fgRedefIdentifier);
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
DOMElement* groupElem = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_Group,
|
|
SchemaSymbols::fgELT_GROUP, fBuffer.getRawBuffer(), &fSchemaInfo);
|
|
|
|
if (groupElem != 0) {
|
|
baseGroup = traverseGroupDecl(groupElem);
|
|
newGroupInfo->setBaseGroup(baseGroup);
|
|
fSchemaInfo = saveInfo;
|
|
}
|
|
else
|
|
{
|
|
reportSchemaError(aLocator, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNotFound,
|
|
SchemaSymbols::fgELT_GROUP, fTargetNSURIString, fBuffer.getRawBuffer());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return newGroupInfo;
|
|
}
|
|
|
|
|
|
/**
|
|
* Traverse attributeGroup Declaration.
|
|
*
|
|
* <attributeGroup
|
|
* id = ID
|
|
* name = NCName
|
|
* ref = QName>
|
|
* Content: (annotation? , (attribute|attributeGroup)*, anyAttribute?)
|
|
* <attributeGroup/>
|
|
*
|
|
*/
|
|
XercesAttGroupInfo*
|
|
TraverseSchema::traverseAttributeGroupDecl(const DOMElement* const elem,
|
|
ComplexTypeInfo* const typeInfo,
|
|
const bool topLevel) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
const XMLCh* name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
const XMLCh* ref = getElementAttValue(elem, SchemaSymbols::fgATT_REF, DatatypeValidator::QName);
|
|
bool nameEmpty = (!name || !*name) ? true : false;
|
|
bool refEmpty = (!ref || !*ref) ? true : false;
|
|
|
|
if (nameEmpty && topLevel) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameGlobalElement,
|
|
SchemaSymbols::fgELT_ATTRIBUTEGROUP);
|
|
return 0;
|
|
}
|
|
|
|
if (nameEmpty && refEmpty) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameRefAttGroup);
|
|
return 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Check attributes
|
|
// ------------------------------------------------------------------
|
|
unsigned short scope = (topLevel) ? GeneralAttributeCheck::E_AttributeGroupGlobal
|
|
: GeneralAttributeCheck::E_AttributeGroupRef;
|
|
fAttributeCheck.checkAttributes(elem, scope, this, topLevel, fNonXSAttList);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Handle "ref="
|
|
// ------------------------------------------------------------------
|
|
XercesAttGroupInfo* attGroupInfo;
|
|
Janitor<XercesAttGroupInfo> janAttGroupInfo(0);
|
|
if (!topLevel) {
|
|
|
|
if (refEmpty) {
|
|
return 0;
|
|
}
|
|
|
|
attGroupInfo = processAttributeGroupRef(elem, ref, typeInfo);
|
|
}
|
|
else
|
|
{
|
|
// name must be a valid NCName
|
|
if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName,
|
|
SchemaSymbols::fgELT_ATTRIBUTEGROUP, name);
|
|
return 0;
|
|
}
|
|
|
|
// Check for annotations
|
|
DOMElement* content = checkContent(elem, XUtil::getFirstChildElement(elem), true);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
}
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
|
|
// Process contents of global attributeGroups
|
|
XercesAttGroupInfo* saveAttGroupInfo = fCurrentAttGroupInfo;
|
|
janAttGroupInfo.reset(new (fGrammarPoolMemoryManager) XercesAttGroupInfo(
|
|
fStringPool->addOrFind(name), fTargetNSURI, fGrammarPoolMemoryManager));
|
|
|
|
fDeclStack->addElement(elem);
|
|
fCurrentAttGroupInfo = janAttGroupInfo.get();
|
|
|
|
for (; content !=0; content = XUtil::getNextSiblingElement(content)) {
|
|
|
|
if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_ATTRIBUTE)) {
|
|
traverseAttributeDecl(content, typeInfo);
|
|
}
|
|
else if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_ATTRIBUTEGROUP)) {
|
|
traverseAttributeGroupDecl(content, typeInfo);
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (content != 0) {
|
|
|
|
if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_ANYATTRIBUTE)) {
|
|
|
|
SchemaAttDef* anyAtt = traverseAnyAttribute(content);
|
|
|
|
if (anyAtt) {
|
|
fCurrentAttGroupInfo->addAnyAttDef(anyAtt);
|
|
}
|
|
|
|
if (XUtil::getNextSiblingElement(content) != 0) {
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::AttGroupContentError, name);
|
|
}
|
|
}
|
|
else {
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::AttGroupContentError, name);
|
|
}
|
|
}
|
|
|
|
// Pop declaration
|
|
fDeclStack->removeElementAt(fDeclStack->size() - 1);
|
|
|
|
fAttGroupRegistry->put((void*) fStringPool->getValueForId(fStringPool->addOrFind(name)), janAttGroupInfo.get());
|
|
// Restore old attGroupInfo
|
|
attGroupInfo = janAttGroupInfo.release();
|
|
fCurrentAttGroupInfo = saveAttGroupInfo;
|
|
|
|
// Check Attribute Derivation Restriction OK
|
|
fBuffer.set(fTargetNSURIString);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(name);
|
|
|
|
unsigned int nameIndex = fStringPool->addOrFind(fBuffer.getRawBuffer());
|
|
|
|
if (fRedefineComponents && fRedefineComponents->get(SchemaSymbols::fgELT_ATTRIBUTEGROUP, nameIndex)) {
|
|
|
|
fBuffer.set(name);
|
|
fBuffer.append(SchemaSymbols::fgRedefIdentifier);
|
|
XercesAttGroupInfo* baseAttGroupInfo = fAttGroupRegistry->get(fBuffer.getRawBuffer());
|
|
|
|
if (baseAttGroupInfo)
|
|
checkAttDerivationOK(elem, baseAttGroupInfo, attGroupInfo);
|
|
}
|
|
|
|
// Store annotation
|
|
if (!janAnnot.isDataNull())
|
|
fSchemaGrammar->putAnnotation(attGroupInfo, janAnnot.release());
|
|
}
|
|
|
|
// calculate complete wildcard if necessary
|
|
if (attGroupInfo)
|
|
{
|
|
XMLSize_t anyAttCount = attGroupInfo->anyAttributeCount();
|
|
if (anyAttCount && !attGroupInfo->getCompleteWildCard())
|
|
{
|
|
SchemaAttDef* attGroupWildCard = new (fGrammarPoolMemoryManager)
|
|
SchemaAttDef(attGroupInfo->anyAttributeAt(0));
|
|
|
|
for (XMLSize_t k= 1; k < anyAttCount; k++)
|
|
attWildCardIntersection(attGroupWildCard, attGroupInfo->anyAttributeAt(k));
|
|
|
|
attGroupInfo->setCompleteWildCard(attGroupWildCard);
|
|
}
|
|
}
|
|
|
|
return attGroupInfo;
|
|
}
|
|
|
|
|
|
inline XercesAttGroupInfo*
|
|
TraverseSchema::traverseAttributeGroupDeclNS(const DOMElement* const elem,
|
|
const XMLCh* const uriStr,
|
|
const XMLCh* const name) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Get grammar information
|
|
// ------------------------------------------------------------------
|
|
Grammar* aGrammar = fGrammarResolver->getGrammar(uriStr);
|
|
|
|
if (!aGrammar || aGrammar->getGrammarType() != Grammar::SchemaGrammarType) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::GrammarNotFound, uriStr);
|
|
return 0;
|
|
}
|
|
|
|
XercesAttGroupInfo* attGroupInfo = ((SchemaGrammar*)aGrammar)->getAttGroupInfoRegistry()->get(name);
|
|
|
|
return attGroupInfo;
|
|
}
|
|
|
|
/**
|
|
* Traverse Any declaration
|
|
*
|
|
* <any
|
|
* id = ID
|
|
* maxOccurs = (nonNegativeInteger | unbounded) : 1
|
|
* minOccurs = nonNegativeInteger : 1
|
|
* namespace = ((##any | ##other) | List of (anyURI |
|
|
* (##targetNamespace | ##local)) ) : ##any
|
|
* processContents = (lax | skip | strict) : strict
|
|
* {any attributes with non-schema namespace . . .}>
|
|
* Content: (annotation?)
|
|
* </any>
|
|
*/
|
|
ContentSpecNode*
|
|
TraverseSchema::traverseAny(const DOMElement* const elem) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check Attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
elem, GeneralAttributeCheck::E_Any, this, false, fNonXSAttList
|
|
);
|
|
|
|
// ------------------------------------------------------------------
|
|
// First, handle any ANNOTATION declaration
|
|
// ------------------------------------------------------------------
|
|
if (checkContent(elem, XUtil::getFirstChildElement(elem), true) != 0)
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
}
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Get attributes
|
|
// ------------------------------------------------------------------
|
|
const XMLCh* const processContents = getElementAttValue(elem, SchemaSymbols::fgATT_PROCESSCONTENTS);
|
|
const XMLCh* const nameSpace = getElementAttValue(elem, SchemaSymbols::fgATT_NAMESPACE);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Set default node type based on 'processContents' value
|
|
// ------------------------------------------------------------------
|
|
ContentSpecNode::NodeTypes anyType = ContentSpecNode::Any;
|
|
ContentSpecNode::NodeTypes anyLocalType = ContentSpecNode::Any_NS;
|
|
ContentSpecNode::NodeTypes anyOtherType = ContentSpecNode::Any_Other;
|
|
|
|
if ((processContents && *processContents)
|
|
&& !XMLString::equals(processContents, SchemaSymbols::fgATTVAL_STRICT)) {
|
|
|
|
if (XMLString::equals(processContents, SchemaSymbols::fgATTVAL_LAX)) {
|
|
|
|
anyType = ContentSpecNode::Any_Lax;
|
|
anyOtherType = ContentSpecNode::Any_Other_Lax;
|
|
anyLocalType = ContentSpecNode::Any_NS_Lax;
|
|
}
|
|
else if (XMLString::equals(processContents, SchemaSymbols::fgATTVAL_SKIP)) {
|
|
|
|
anyType = ContentSpecNode::Any_Skip;
|
|
anyOtherType = ContentSpecNode::Any_Other_Skip;
|
|
anyLocalType = ContentSpecNode::Any_NS_Skip;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Process 'namespace' attribute
|
|
// ------------------------------------------------------------------
|
|
ContentSpecNode* retSpecNode = 0;
|
|
|
|
if ((!nameSpace || !*nameSpace)
|
|
|| XMLString::equals(nameSpace, SchemaSymbols::fgATTVAL_TWOPOUNDANY)) {
|
|
retSpecNode = new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
new (fGrammarPoolMemoryManager) QName
|
|
(
|
|
XMLUni::fgZeroLenString
|
|
, XMLUni::fgZeroLenString
|
|
, fEmptyNamespaceURI
|
|
, fGrammarPoolMemoryManager
|
|
)
|
|
, false
|
|
, fGrammarPoolMemoryManager
|
|
);
|
|
retSpecNode->setType(anyType);
|
|
}
|
|
else if (XMLString::equals(nameSpace, SchemaSymbols::fgATTVAL_TWOPOUNDOTHER)) {
|
|
retSpecNode = new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
new (fGrammarPoolMemoryManager) QName
|
|
(
|
|
XMLUni::fgZeroLenString
|
|
, XMLUni::fgZeroLenString
|
|
, fTargetNSURI, fGrammarPoolMemoryManager
|
|
)
|
|
, false
|
|
, fGrammarPoolMemoryManager
|
|
);
|
|
retSpecNode->setType(anyOtherType);
|
|
}
|
|
else {
|
|
|
|
XMLStringTokenizer nameSpaceTokens(nameSpace, fMemoryManager);
|
|
ValueVectorOf<unsigned int> uriList(8, fGrammarPoolMemoryManager);
|
|
Janitor<ContentSpecNode> firstNode(0);
|
|
Janitor<ContentSpecNode> secondNode(0);
|
|
DatatypeValidator* anyURIDV = fDatatypeRegistry->getDatatypeValidator(SchemaSymbols::fgDT_ANYURI);
|
|
|
|
while (nameSpaceTokens.hasMoreTokens()) {
|
|
|
|
const XMLCh* tokenElem = nameSpaceTokens.nextToken();
|
|
int uriIndex = fEmptyNamespaceURI;
|
|
|
|
if (!XMLString::equals(tokenElem,SchemaSymbols::fgATTVAL_TWOPOUNDLOCAL)) { // not ##local
|
|
|
|
if (XMLString::equals(tokenElem,SchemaSymbols::fgATTVAL_TWOPOUNDTRAGETNAMESPACE)) {
|
|
uriIndex = fTargetNSURI;
|
|
}
|
|
else {
|
|
try {
|
|
anyURIDV->validate(tokenElem
|
|
, fSchemaInfo->getValidationContext()
|
|
, fMemoryManager);
|
|
}
|
|
catch(const XMLException& excep) {
|
|
reportSchemaError(elem, excep);
|
|
}
|
|
uriIndex = fURIStringPool->addOrFind(tokenElem);
|
|
}
|
|
}
|
|
|
|
if (uriList.containsElement(uriIndex)) {
|
|
continue;
|
|
}
|
|
|
|
uriList.addElement(uriIndex);
|
|
|
|
firstNode.release();
|
|
firstNode.reset( new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
new (fGrammarPoolMemoryManager) QName
|
|
(
|
|
XMLUni::fgZeroLenString
|
|
, XMLUni::fgZeroLenString
|
|
, uriIndex, fGrammarPoolMemoryManager
|
|
)
|
|
, false
|
|
, fGrammarPoolMemoryManager
|
|
));
|
|
firstNode.get()->setType(anyLocalType);
|
|
|
|
if (secondNode.get() == 0) {
|
|
secondNode.reset(firstNode.release());
|
|
}
|
|
else {
|
|
ContentSpecNode* newNode = new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
ContentSpecNode::Any_NS_Choice
|
|
, secondNode.get()
|
|
, firstNode.get()
|
|
, true
|
|
, true
|
|
, fGrammarPoolMemoryManager
|
|
);
|
|
secondNode.release();
|
|
secondNode.reset(newNode);
|
|
firstNode.release();
|
|
}
|
|
}
|
|
firstNode.release();
|
|
retSpecNode = secondNode.release();
|
|
}
|
|
|
|
// Store annotation
|
|
if (retSpecNode && !janAnnot.isDataNull())
|
|
fSchemaGrammar->putAnnotation(retSpecNode, janAnnot.release());
|
|
|
|
return retSpecNode;
|
|
}
|
|
|
|
|
|
/**
|
|
* Traverse all
|
|
*
|
|
* <all
|
|
* id = ID
|
|
* maxOccurs = 1 : 1
|
|
* minOccurs = (0 | 1) : 1
|
|
* {any attributes with non-schema namespace . . .}>
|
|
* Content: (annotation?, element*)
|
|
* </all>
|
|
*/
|
|
ContentSpecNode*
|
|
TraverseSchema::traverseAll(const DOMElement* const elem, bool& hasChildren) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
hasChildren = false;
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
elem, GeneralAttributeCheck::E_All, this, false, fNonXSAttList
|
|
);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Process contents
|
|
// -----------------------------------------------------------------------
|
|
DOMElement* child = checkContent(elem, XUtil::getFirstChildElement(elem), true);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
}
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
|
|
if (child == 0) {
|
|
return 0;
|
|
}
|
|
|
|
Janitor<ContentSpecNode> left(0);
|
|
Janitor<ContentSpecNode> right(0);
|
|
Janitor<ContentSpecNode> contentSpecNode(0);
|
|
bool hadContent = false;
|
|
|
|
for (; child != 0; child = XUtil::getNextSiblingElement(child)) {
|
|
hasChildren = true;
|
|
contentSpecNode.release();
|
|
const XMLCh* childName = child->getLocalName();
|
|
|
|
if (XMLString::equals(childName, SchemaSymbols::fgELT_ELEMENT)) {
|
|
|
|
SchemaElementDecl* elemDecl = traverseElementDecl(child);
|
|
|
|
if (!elemDecl)
|
|
continue;
|
|
|
|
contentSpecNode.reset(new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
elemDecl
|
|
, fGrammarPoolMemoryManager
|
|
));
|
|
checkMinMax(contentSpecNode.get(), child, All_Element);
|
|
}
|
|
else {
|
|
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::AllContentError, childName);
|
|
continue;
|
|
}
|
|
|
|
hadContent = true;
|
|
|
|
if (!left.get()) {
|
|
left.reset(contentSpecNode.release());
|
|
}
|
|
else if (!right.get()) {
|
|
right.reset(contentSpecNode.release());
|
|
}
|
|
else {
|
|
ContentSpecNode* newNode = new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
ContentSpecNode::All
|
|
, left.get()
|
|
, right.get()
|
|
, true
|
|
, true
|
|
, fGrammarPoolMemoryManager
|
|
);
|
|
left.release();
|
|
left.reset(newNode);
|
|
right.release();
|
|
right.reset(contentSpecNode.release());
|
|
}
|
|
}
|
|
contentSpecNode.release();
|
|
|
|
if (hadContent) {
|
|
ContentSpecNode* newNode = new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
ContentSpecNode::All
|
|
, left.get()
|
|
, right.get()
|
|
, true
|
|
, true
|
|
, fGrammarPoolMemoryManager
|
|
);
|
|
|
|
left.release();
|
|
left.reset(newNode);
|
|
|
|
if (!janAnnot.isDataNull())
|
|
fSchemaGrammar->putAnnotation(left.get(), janAnnot.release());
|
|
}
|
|
right.release();
|
|
return left.release();
|
|
}
|
|
|
|
/**
|
|
* Traverses Schema attribute declaration.
|
|
*
|
|
* <attribute
|
|
* fixed = string
|
|
* default = string
|
|
* form = qualified | unqualified
|
|
* id = ID
|
|
* name = NCName
|
|
* ref = QName
|
|
* type = QName
|
|
* use = optional | prohibited | required : optional
|
|
>
|
|
* Content: (annotation? , simpleType?)
|
|
* <attribute/>
|
|
*
|
|
* @param elem: the declaration of the attribute under consideration
|
|
*
|
|
* @param typeInfo: Contains the complex type info of the element to which
|
|
* the attribute declaration is attached.
|
|
*
|
|
*/
|
|
void TraverseSchema::traverseAttributeDecl(const DOMElement* const elem,
|
|
ComplexTypeInfo* const typeInfo,
|
|
const bool topLevel) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
const XMLCh* name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
const XMLCh* ref = getElementAttValue(elem, SchemaSymbols::fgATT_REF, DatatypeValidator::QName);
|
|
bool nameEmpty = (!name || !*name);
|
|
bool refEmpty = (!ref || !*ref);
|
|
|
|
if (nameEmpty && refEmpty) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameRefAttribute);
|
|
return;
|
|
}
|
|
|
|
if (topLevel && nameEmpty) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TopLevelNoNameAttribute);
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Check attributes
|
|
// ------------------------------------------------------------------
|
|
unsigned short scope = (topLevel)
|
|
? GeneralAttributeCheck::E_AttributeGlobal
|
|
: (refEmpty) ? GeneralAttributeCheck::E_AttributeLocal
|
|
: GeneralAttributeCheck::E_AttributeRef;
|
|
|
|
fAttributeCheck.checkAttributes(elem, scope, this, topLevel, fNonXSAttList);
|
|
|
|
const XMLCh* defaultVal = getElementAttValue(elem, SchemaSymbols::fgATT_DEFAULT);
|
|
const XMLCh* fixedVal = getElementAttValue(elem, SchemaSymbols::fgATT_FIXED);
|
|
const XMLCh* useVal = getElementAttValue(elem, SchemaSymbols::fgATT_USE);
|
|
const XMLCh* attForm = getElementAttValue(elem, SchemaSymbols::fgATT_FORM);
|
|
const XMLCh* dvType = getElementAttValue(elem, SchemaSymbols::fgATT_TYPE, DatatypeValidator::QName);
|
|
DOMElement* simpleType = checkContent(elem, XUtil::getFirstChildElement(elem), true);
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
bool badContent = false;
|
|
|
|
while (simpleType != 0) {
|
|
|
|
const XMLCh* contentName = simpleType->getLocalName();
|
|
|
|
if (XMLString::equals(SchemaSymbols::fgELT_SIMPLETYPE, contentName)) {
|
|
|
|
if (XUtil::getNextSiblingElement(simpleType) != 0) {
|
|
badContent = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
badContent = true;
|
|
simpleType = XUtil::getNextSiblingElement(simpleType);
|
|
}
|
|
|
|
if (badContent) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidAttributeContent,
|
|
(name) ? name : ref);
|
|
}
|
|
|
|
if (defaultVal) {
|
|
|
|
if (fixedVal) {
|
|
|
|
fixedVal = 0;
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttributeDefaultFixedValue,
|
|
(name) ? name : ref);
|
|
}
|
|
|
|
if ((useVal && *useVal)
|
|
&& !XMLString::equals(useVal, SchemaSymbols::fgATTVAL_OPTIONAL)) {
|
|
|
|
useVal = 0;
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NotOptionalDefaultAttValue,
|
|
(name) ? name : ref);
|
|
}
|
|
}
|
|
|
|
// processing ref
|
|
if (!refEmpty && !topLevel) {
|
|
|
|
// Check ref representation OK - 3.2.3::3.2
|
|
if (attForm || dvType || (simpleType != 0)) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttributeRefContentError,
|
|
(name) ? name : ref);
|
|
}
|
|
|
|
processAttributeDeclRef(elem, typeInfo, ref, useVal, defaultVal, fixedVal);
|
|
return;
|
|
}
|
|
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
janAnnot.reset(fAnnotation);
|
|
}
|
|
|
|
// processing 'name'
|
|
if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))
|
|
|| XMLString::equals(name, XMLUni::fgXMLNSString)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName, SchemaSymbols::fgELT_ATTRIBUTE, name);
|
|
return;
|
|
}
|
|
|
|
// Check for duplicate declaration
|
|
const XMLCh* qualified = SchemaSymbols::fgATTVAL_QUALIFIED;
|
|
int uriIndex = fEmptyNamespaceURI;
|
|
|
|
if ((fTargetNSURIString && *fTargetNSURIString)
|
|
&& (topLevel || XMLString::equals(attForm, qualified)
|
|
|| ((fSchemaInfo->getElemAttrDefaultQualified() & Attr_Def_Qualified)
|
|
&& (!attForm || !*attForm)))) {
|
|
uriIndex = fTargetNSURI;
|
|
}
|
|
|
|
// make sure that attribute namespace is not xsi uri
|
|
if (XMLString::equals(fTargetNSURIString, SchemaSymbols::fgURI_XSI)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidAttTNS, name);
|
|
return;
|
|
}
|
|
|
|
if (typeInfo && typeInfo->getAttDef(name, uriIndex) != 0) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttribute, name);
|
|
return;
|
|
}
|
|
else if (fCurrentAttGroupInfo && fCurrentAttGroupInfo->containsAttribute(name, uriIndex)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttribute, name);
|
|
return;
|
|
}
|
|
|
|
DatatypeValidator* dv = 0;
|
|
XMLAttDef::AttTypes attType = XMLAttDef::Simple;
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
|
|
if (simpleType != 0) {
|
|
|
|
if (dvType && *dvType) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttributeWithTypeAndSimpleType, name);
|
|
}
|
|
|
|
dv = traverseSimpleTypeDecl(simpleType, false);
|
|
}
|
|
else if (!dvType || !*dvType) {
|
|
dv = fDatatypeRegistry->getDatatypeValidator(SchemaSymbols::fgDT_ANYSIMPLETYPE);
|
|
}
|
|
else {
|
|
|
|
checkEnumerationRequiredNotation(elem, name, dvType);
|
|
|
|
const XMLCh* localPart = getLocalPart(dvType);
|
|
const XMLCh* prefix = getPrefix(dvType);
|
|
const XMLCh* typeURI = resolvePrefixToURI(elem, prefix);
|
|
DatatypeValidator* dvBack = 0;
|
|
|
|
if (XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {
|
|
dv = fDatatypeRegistry->getDatatypeValidator(localPart);
|
|
dvBack = dv;
|
|
}
|
|
else { //isn't of the schema for schemas namespace...
|
|
|
|
dv = getAttrDatatypeValidatorNS(elem, localPart, typeURI);
|
|
dvBack = dv;
|
|
|
|
while(dv != 0 && !XMLString::equals(dv->getTypeUri(), SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {
|
|
dv = dv->getBaseValidator();
|
|
}
|
|
|
|
if(dv)
|
|
localPart = dv->getTypeLocalName();
|
|
}
|
|
|
|
if(dv) {
|
|
if (XMLString::equals(localPart,XMLUni::fgIDString)) {
|
|
attType = XMLAttDef::ID;
|
|
}
|
|
else if (XMLString::equals(localPart,XMLUni::fgIDRefString)) {
|
|
attType = XMLAttDef::IDRef;
|
|
}
|
|
else if (XMLString::equals(localPart,XMLUni::fgIDRefsString)) {
|
|
attType = XMLAttDef::IDRefs;
|
|
}
|
|
else if (XMLString::equals(localPart,XMLUni::fgEntityString)) {
|
|
attType = XMLAttDef::Entity;
|
|
}
|
|
else if (XMLString::equals(localPart,XMLUni::fgEntitiesString)) {
|
|
attType = XMLAttDef::Entities;
|
|
}
|
|
else if (XMLString::equals(localPart,XMLUni::fgNmTokenString)) {
|
|
attType = XMLAttDef::NmToken;
|
|
}
|
|
else if (XMLString::equals(localPart,XMLUni::fgNmTokensString)) {
|
|
attType = XMLAttDef::NmTokens;
|
|
}
|
|
else if (XMLString::equals(localPart,XMLUni::fgNotationString)) {
|
|
attType = XMLAttDef::Notation;
|
|
}
|
|
else {
|
|
attType = XMLAttDef::Simple;
|
|
}
|
|
}
|
|
else
|
|
attType = XMLAttDef::Simple;
|
|
|
|
dv = dvBack;
|
|
|
|
if (!dv) {
|
|
reportSchemaError
|
|
(
|
|
elem
|
|
, XMLUni::fgXMLErrDomain
|
|
, XMLErrs::AttributeSimpleTypeNotFound
|
|
, typeURI
|
|
, localPart
|
|
, name
|
|
);
|
|
}
|
|
}
|
|
|
|
// restore schema information, if necessary
|
|
fSchemaInfo = saveInfo;
|
|
|
|
bool required = false;
|
|
bool prohibited = false;
|
|
|
|
if (useVal && *useVal) {
|
|
|
|
if (XMLString::equals(useVal, SchemaSymbols::fgATTVAL_REQUIRED)) {
|
|
required = true;
|
|
}
|
|
else if (XMLString::equals(useVal, SchemaSymbols::fgATTVAL_PROHIBITED)) {
|
|
prohibited = true;
|
|
}
|
|
}
|
|
|
|
// validate fixed/default values
|
|
const XMLCh* valueToCheck = defaultVal ? defaultVal : fixedVal;
|
|
bool ofTypeID = (dv && dv->getType() == DatatypeValidator::ID);
|
|
|
|
if (attType == XMLAttDef::Simple && dv && valueToCheck) {
|
|
|
|
short wsFacet = dv->getWSFacet();
|
|
if((wsFacet == DatatypeValidator::REPLACE && !XMLString::isWSReplaced(valueToCheck)) ||
|
|
(wsFacet == DatatypeValidator::COLLAPSE && !XMLString::isWSCollapsed(valueToCheck)))
|
|
{
|
|
XMLCh* normalizedValue=XMLString::replicate(valueToCheck, fMemoryManager);
|
|
ArrayJanitor<XMLCh> tempURIName(normalizedValue, fMemoryManager);
|
|
if(wsFacet == DatatypeValidator::REPLACE)
|
|
XMLString::replaceWS(normalizedValue, fMemoryManager);
|
|
else if(wsFacet == DatatypeValidator::COLLAPSE)
|
|
XMLString::collapseWS(normalizedValue, fMemoryManager);
|
|
valueToCheck=fStringPool->getValueForId(fStringPool->addOrFind(normalizedValue));
|
|
}
|
|
try {
|
|
dv->validate(valueToCheck
|
|
, fSchemaInfo->getValidationContext()
|
|
, fMemoryManager);
|
|
}
|
|
catch (const XMLException& excep) {
|
|
reportSchemaError(elem, excep);
|
|
}
|
|
catch(const OutOfMemoryException&)
|
|
{
|
|
throw;
|
|
}
|
|
catch(...) {
|
|
reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::DatatypeValidationFailure, valueToCheck);
|
|
}
|
|
}
|
|
else if((attType == XMLAttDef::NmTokens || attType==XMLAttDef::IDRefs || attType==XMLAttDef::Entities) &&
|
|
valueToCheck && !XMLString::isWSCollapsed(valueToCheck))
|
|
{
|
|
XMLCh* normalizedValue=XMLString::replicate(valueToCheck, fMemoryManager);
|
|
ArrayJanitor<XMLCh> tempURIName(normalizedValue, fMemoryManager);
|
|
XMLString::collapseWS(normalizedValue, fMemoryManager);
|
|
valueToCheck=fStringPool->getValueForId(fStringPool->addOrFind(normalizedValue));
|
|
}
|
|
|
|
if (ofTypeID && valueToCheck) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttDeclPropCorrect3, name);
|
|
}
|
|
|
|
// check for multiple attributes with type derived from ID
|
|
if (!topLevel && ofTypeID) {
|
|
|
|
if (fCurrentAttGroupInfo) {
|
|
|
|
if (fCurrentAttGroupInfo->containsTypeWithId()) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttGrpPropCorrect3, name);
|
|
return;
|
|
}
|
|
|
|
fCurrentAttGroupInfo->setTypeWithId(true);
|
|
}
|
|
else {
|
|
|
|
if (typeInfo->containsAttWithTypeId()) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttDeclPropCorrect5, name);
|
|
return;
|
|
}
|
|
|
|
typeInfo->setAttWithTypeId(true);
|
|
}
|
|
}
|
|
|
|
// create SchemaAttDef
|
|
SchemaAttDef* attDef = new (fGrammarPoolMemoryManager) SchemaAttDef
|
|
(
|
|
XMLUni::fgZeroLenString
|
|
, name
|
|
, uriIndex
|
|
, attType
|
|
, XMLAttDef::Implied
|
|
, fGrammarPoolMemoryManager
|
|
);
|
|
|
|
attDef->setDatatypeValidator(dv);
|
|
|
|
if (prohibited) {
|
|
attDef->setDefaultType(XMLAttDef::Prohibited);
|
|
}
|
|
else if (required) {
|
|
|
|
if (fixedVal) {
|
|
attDef->setDefaultType(XMLAttDef::Required_And_Fixed);
|
|
}
|
|
else {
|
|
attDef->setDefaultType(XMLAttDef::Required);
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (fixedVal) {
|
|
attDef->setDefaultType(XMLAttDef::Fixed);
|
|
}
|
|
else if (defaultVal) {
|
|
attDef->setDefaultType(XMLAttDef::Default);
|
|
}
|
|
}
|
|
|
|
if (valueToCheck) {
|
|
attDef->setValue(valueToCheck);
|
|
}
|
|
|
|
if (!janAnnot.isDataNull())
|
|
fSchemaGrammar->putAnnotation(attDef, janAnnot.release());
|
|
|
|
if (topLevel)
|
|
{
|
|
fAttributeDeclRegistry->put((void*) fStringPool->getValueForId(fStringPool->addOrFind(name)), attDef);
|
|
attDef->setPSVIScope(PSVIDefs::SCP_GLOBAL);
|
|
}
|
|
else
|
|
{
|
|
if (typeInfo)
|
|
{
|
|
typeInfo->addAttDef(attDef);
|
|
if (!fCurrentAttGroupInfo)
|
|
attDef->setPSVIScope(PSVIDefs::SCP_LOCAL);
|
|
}
|
|
|
|
if (fCurrentAttGroupInfo) {
|
|
fCurrentAttGroupInfo->addAttDef(attDef, (typeInfo != 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Traverses Schema element declaration.
|
|
*
|
|
* <element
|
|
* abstract = boolean : false
|
|
* block = (#all | List of (substitution | extension | restriction
|
|
* | list | union))
|
|
* default = string
|
|
* final = (#all | List of (extension | restriction))
|
|
* fixed = string
|
|
* form = (qualified | unqualified)
|
|
* id = ID
|
|
* maxOccurs = (nonNegativeInteger | unbounded) : 1
|
|
* minOccurs = nonNegativeInteger : 1
|
|
* name = NCName
|
|
* nillable = boolean : false
|
|
* ref = QName
|
|
* substitutionGroup = QName
|
|
* type = QName
|
|
* Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*))
|
|
* </element>
|
|
*
|
|
* @param elem: the declaration of the element under consideration
|
|
*/
|
|
SchemaElementDecl*
|
|
TraverseSchema::traverseElementDecl(const DOMElement* const elem,
|
|
const bool topLevel)
|
|
{
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
// if local element and ref attribute exists
|
|
if (!topLevel)
|
|
{
|
|
const XMLCh* refName = getElementAttValue(elem, SchemaSymbols::fgATT_REF, DatatypeValidator::QName);
|
|
if (refName)
|
|
return processElementDeclRef(elem, refName);
|
|
}
|
|
|
|
// check for empty name
|
|
const XMLCh* name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
if (!name || !*name)
|
|
{
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameRefElement);
|
|
return 0;
|
|
}
|
|
|
|
// make sure that name is a valid NCName
|
|
if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name)))
|
|
{
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain,
|
|
XMLErrs::InvalidDeclarationName, SchemaSymbols::fgELT_ELEMENT, name);
|
|
return 0;
|
|
}
|
|
|
|
// if element already exists, just return --- revisit, it should not happen
|
|
if (topLevel)
|
|
{
|
|
SchemaElementDecl* retDecl = (SchemaElementDecl*) fSchemaGrammar->getElemDecl(fTargetNSURI, name, 0, Grammar::TOP_LEVEL_SCOPE);
|
|
if (retDecl)
|
|
return retDecl;
|
|
}
|
|
|
|
// Check attributes
|
|
unsigned short scope = (topLevel) ? GeneralAttributeCheck::E_ElementGlobal
|
|
: GeneralAttributeCheck::E_ElementLocal;
|
|
|
|
fAttributeCheck.checkAttributes(elem, scope, this, topLevel, fNonXSAttList);
|
|
|
|
// check annotation
|
|
const DOMElement* content = checkContent(elem, XUtil::getFirstChildElement(elem), true);
|
|
// Put annotations on all elements for the situation where there is a group of
|
|
// elements and not all have annotations.
|
|
//if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
if (!fAnnotation && fScanner->getGenerateSyntheticAnnotations())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
}
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
|
|
// Create element decl
|
|
bool isDuplicate = false;
|
|
const XMLCh* valueConstraint = 0;
|
|
SchemaElementDecl* elemDecl =
|
|
createSchemaElementDecl(elem, name, isDuplicate, valueConstraint, topLevel);
|
|
|
|
if (!isDuplicate) {
|
|
|
|
fSchemaGrammar->putElemDecl(elemDecl);
|
|
|
|
if (valueConstraint)
|
|
elemDecl->setDefaultValue(valueConstraint);
|
|
|
|
if (!janAnnot.isDataNull())
|
|
fSchemaGrammar->putAnnotation(elemDecl, janAnnot.release());
|
|
|
|
if (fCurrentComplexType &&
|
|
elemDecl->getEnclosingScope() == fCurrentComplexType->getScopeDefined()) {
|
|
fCurrentComplexType->addElement(elemDecl);
|
|
elemDecl->setPSVIScope(PSVIDefs::SCP_LOCAL);
|
|
}
|
|
|
|
if (fCurrentGroupInfo &&
|
|
elemDecl->getEnclosingScope() == fCurrentGroupInfo->getScope()) {
|
|
fCurrentGroupInfo->addElement(elemDecl);
|
|
elemDecl->setPSVIScope(PSVIDefs::SCP_ABSENT);
|
|
}
|
|
}
|
|
else {
|
|
if (fAnnotation) {
|
|
XSAnnotation* xsAnnot = fSchemaGrammar->getAnnotation(elemDecl);
|
|
if (!xsAnnot) {
|
|
fSchemaGrammar->putAnnotation(elemDecl, janAnnot.release());
|
|
}
|
|
else {
|
|
xsAnnot->setNext(janAnnot.release());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process children
|
|
bool anonymousType = false;
|
|
ComplexTypeInfo* typeInfo = 0;
|
|
DatatypeValidator* validator = 0;
|
|
|
|
if (content != 0)
|
|
{
|
|
const XMLCh* contentName = content->getLocalName();
|
|
|
|
if (XMLString::equals(contentName, SchemaSymbols::fgELT_COMPLEXTYPE))
|
|
{
|
|
const XMLCh* temp = content->getAttribute(SchemaSymbols::fgATT_NAME);
|
|
|
|
if (temp && *temp)
|
|
{
|
|
// REVISIT - we are bypassing the complex type declaration.
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::AnonComplexTypeWithName, name);
|
|
}
|
|
else
|
|
{
|
|
typeInfo = checkForComplexTypeInfo(content);
|
|
|
|
if (typeInfo)
|
|
{
|
|
validator = typeInfo->getDatatypeValidator();
|
|
|
|
if (!isDuplicate) {
|
|
|
|
//Recursing element
|
|
if (typeInfo->getPreprocessed()) {
|
|
|
|
const XMLCh* typeInfoName = typeInfo->getTypeName();
|
|
fSchemaInfo->addRecursingType(content, typeInfoName + XMLString::indexOf(typeInfoName, chComma) + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
anonymousType = true;
|
|
content = XUtil::getNextSiblingElement(content);
|
|
}
|
|
else if (XMLString::equals(contentName, SchemaSymbols::fgELT_SIMPLETYPE))
|
|
{
|
|
const XMLCh* temp = content->getAttribute(SchemaSymbols::fgATT_NAME);
|
|
if (temp && *temp)
|
|
// REVISIT - we are bypassing the simple type declaration.
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::AnonSimpleTypeWithName, name);
|
|
else
|
|
validator = checkForSimpleTypeValidator(content);
|
|
|
|
anonymousType = true;
|
|
content = XUtil::getNextSiblingElement(content);
|
|
}
|
|
|
|
// Check for identity constraints
|
|
if (content != 0)
|
|
{
|
|
content = checkIdentityConstraintContent(content);
|
|
if (content != 0)
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::InvalidElementContent);
|
|
}
|
|
}
|
|
|
|
// Handle 'type' attribute
|
|
const XMLCh* typeStr = getElementAttValue(elem, SchemaSymbols::fgATT_TYPE, DatatypeValidator::QName);
|
|
if (typeStr)
|
|
{
|
|
if (anonymousType)
|
|
{
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::ElementWithTypeAndAnonType, name);
|
|
}
|
|
else if (*typeStr)
|
|
{
|
|
const XMLCh* typeLocalPart = getLocalPart(typeStr);
|
|
const XMLCh* typePrefix = getPrefix(typeStr);
|
|
const XMLCh* typeURI = resolvePrefixToURI(elem, typePrefix);
|
|
|
|
if (!XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)
|
|
|| !XMLString::equals(typeLocalPart, SchemaSymbols::fgATTVAL_ANYTYPE))
|
|
{
|
|
checkEnumerationRequiredNotation(elem, name, typeStr);
|
|
|
|
bool noErrorFound = true;
|
|
const XMLCh* anotherSchemaURI = checkTypeFromAnotherSchema(elem, typeStr);
|
|
|
|
// get complex type info
|
|
typeInfo = getElementComplexTypeInfo(elem, typeStr, anotherSchemaURI);
|
|
|
|
// get simple type validtor - if not a complex type
|
|
if (typeInfo)
|
|
validator = typeInfo->getDatatypeValidator();
|
|
else
|
|
validator = getElementTypeValidator(elem, typeStr, noErrorFound, anotherSchemaURI);
|
|
}
|
|
}
|
|
}
|
|
|
|
// check for duplicate elements with different types.
|
|
if (isDuplicate)
|
|
{
|
|
DatatypeValidator* eltDV = elemDecl->getDatatypeValidator();
|
|
ComplexTypeInfo* eltTypeInfo = elemDecl->getComplexTypeInfo();
|
|
|
|
if ( (eltTypeInfo != typeInfo) || (eltDV != validator)) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateElementDeclaration, name);
|
|
}
|
|
}
|
|
// Set element declararion type information
|
|
else
|
|
{
|
|
elemDecl->setDatatypeValidator(validator);
|
|
elemDecl->setComplexTypeInfo(typeInfo);
|
|
|
|
if (validator)
|
|
elemDecl->setModelType(SchemaElementDecl::Simple);
|
|
else if (typeInfo)
|
|
elemDecl->setModelType((SchemaElementDecl::ModelTypes)typeInfo->getContentType());
|
|
|
|
if (topLevel) {
|
|
|
|
// Handle the substitutionGroup
|
|
const XMLCh* subsGroupName = getElementAttValue(elem, SchemaSymbols::fgATT_SUBSTITUTIONGROUP, DatatypeValidator::QName);
|
|
if (subsGroupName && *subsGroupName)
|
|
processSubstitutionGroup(elem, elemDecl, typeInfo, validator, subsGroupName);
|
|
}
|
|
|
|
// process identity constraints
|
|
DOMElement* ic = XUtil::getFirstChildElementNS(
|
|
elem, fgIdentityConstraints, SchemaSymbols::fgURI_SCHEMAFORSCHEMA, 3);
|
|
|
|
if (ic)
|
|
processElemDeclIC(ic, elemDecl);
|
|
}
|
|
|
|
if (!typeInfo && !validator)
|
|
{
|
|
if (!isDuplicate)
|
|
{
|
|
elemDecl->setModelType(SchemaElementDecl::Any);
|
|
elemDecl->setAttWildCard(
|
|
new (fGrammarPoolMemoryManager) SchemaAttDef(
|
|
XMLUni::fgZeroLenString, XMLUni::fgZeroLenString,
|
|
fEmptyNamespaceURI, XMLAttDef::Any_Any,
|
|
XMLAttDef::ProcessContents_Lax, fGrammarPoolMemoryManager
|
|
)
|
|
);
|
|
}
|
|
}
|
|
else if (valueConstraint)
|
|
{
|
|
if (!checkElemDeclValueConstraint(elem, elemDecl, valueConstraint, typeInfo, validator)
|
|
&& !isDuplicate)
|
|
{
|
|
int miscFlags = elemDecl->getMiscFlags();
|
|
miscFlags &= ~ SchemaSymbols::XSD_FIXED;
|
|
elemDecl->setDefaultValue(0);
|
|
elemDecl->setMiscFlags(miscFlags);
|
|
}
|
|
}
|
|
|
|
return elemDecl;
|
|
}
|
|
|
|
/**
|
|
* Traverses Schema notation declaration.
|
|
*
|
|
* <notation
|
|
* id = ID
|
|
* name = NCName
|
|
* public = token
|
|
* system = anyURI
|
|
* {any attributes with non-schema namespace . . .}>
|
|
* Content: (annotation?)
|
|
* </notation>
|
|
*
|
|
* @param elem: the declaration of the element under consideration
|
|
*/
|
|
const XMLCh* TraverseSchema::traverseNotationDecl(const DOMElement* const elem) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
elem, GeneralAttributeCheck::E_Notation, this, true, fNonXSAttList
|
|
);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Process notation attributes/elements
|
|
// -----------------------------------------------------------------------
|
|
const XMLCh* name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
bool nameEmpty = (!name || !*name) ? true : false;
|
|
|
|
if (nameEmpty) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameGlobalElement,
|
|
SchemaSymbols::fgELT_NOTATION);
|
|
return 0;
|
|
}
|
|
|
|
if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName,
|
|
SchemaSymbols::fgELT_NOTATION, name);
|
|
return 0;
|
|
}
|
|
|
|
if (fNotationRegistry->containsKey(name, fTargetNSURI)) {
|
|
return name;
|
|
}
|
|
|
|
if (checkContent(elem, XUtil::getFirstChildElement(elem), true) != 0)
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected);
|
|
|
|
const XMLCh* publicId = getElementAttValue(elem, SchemaSymbols::fgATT_PUBLIC);
|
|
const XMLCh* systemId = getElementAttValue(elem, SchemaSymbols::fgATT_SYSTEM, DatatypeValidator::AnyURI);
|
|
|
|
fNotationRegistry->put((void*) fStringPool->getValueForId(fStringPool->addOrFind(name)),
|
|
fTargetNSURI, 0);
|
|
|
|
// for PSVI we need to store the notational decl
|
|
XMLNotationDecl* decl = new (fGrammarPoolMemoryManager) XMLNotationDecl
|
|
(
|
|
name,
|
|
publicId,
|
|
systemId,
|
|
0,
|
|
fGrammarPoolMemoryManager
|
|
);
|
|
decl->setNameSpaceId(fTargetNSURI);
|
|
fSchemaGrammar->putNotationDecl(decl);
|
|
|
|
if (fAnnotation)
|
|
fSchemaGrammar->putAnnotation(decl, fAnnotation);
|
|
else if (fScanner->getGenerateSyntheticAnnotations() && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
fSchemaGrammar->putAnnotation(decl, fAnnotation);
|
|
}
|
|
return name;
|
|
}
|
|
|
|
const XMLCh* TraverseSchema::traverseNotationDecl(const DOMElement* const elem,
|
|
const XMLCh* const name,
|
|
const XMLCh* const uriStr) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
unsigned int uriId = fURIStringPool->addOrFind(uriStr);
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
|
|
if (fTargetNSURI != (int) uriId) {
|
|
|
|
// Make sure that we have an explicit import statement.
|
|
// Clause 4 of Schema Representation Constraint:
|
|
// http://www.w3.org/TR/xmlschema-1/#src-resolve
|
|
unsigned int uriId = fURIStringPool->addOrFind(uriStr);
|
|
|
|
if (!isImportingNS(uriId)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, uriStr);
|
|
return 0;
|
|
}
|
|
|
|
Grammar* grammar = fGrammarResolver->getGrammar(uriStr);
|
|
|
|
if (grammar == 0 || grammar->getGrammarType() != Grammar::SchemaGrammarType) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::GrammarNotFound, uriStr);
|
|
return 0;
|
|
}
|
|
|
|
SchemaInfo* impInfo = fSchemaInfo->getImportInfo(uriId);
|
|
|
|
if (!impInfo || impInfo->getProcessed()) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, uriStr, name);
|
|
return 0;
|
|
}
|
|
|
|
fSchemaInfo = impInfo;
|
|
fTargetNSURI = fSchemaInfo->getTargetNSURI();
|
|
}
|
|
|
|
DOMElement* notationElem = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_Notation,
|
|
SchemaSymbols::fgELT_NOTATION, name, &fSchemaInfo);
|
|
|
|
if (notationElem == 0) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::Notation_DeclNotFound, uriStr, name);
|
|
return 0;
|
|
}
|
|
|
|
const XMLCh* notationName = traverseNotationDecl(notationElem);
|
|
|
|
fSchemaInfo = saveInfo;
|
|
fTargetNSURI = fSchemaInfo->getTargetNSURI();
|
|
|
|
return notationName;
|
|
}
|
|
|
|
/**
|
|
* Traverses Schema list simple type declaration.
|
|
*
|
|
* <list
|
|
* id = ID
|
|
* itemType = QName
|
|
* {any attributes with non-schema namespace . . .}>
|
|
* Content: (annotation?, simpleType?)
|
|
* </list>
|
|
*
|
|
*/
|
|
DatatypeValidator*
|
|
TraverseSchema::traverseByList(const DOMElement* const rootElem,
|
|
const DOMElement* const contentElem,
|
|
const XMLCh* const typeName,
|
|
const XMLCh* const qualifiedName,
|
|
const int finalSet,
|
|
Janitor<XSAnnotation>* const janAnnot) {
|
|
|
|
NamespaceScopeManager nsMgr(contentElem, fSchemaInfo, this);
|
|
|
|
DatatypeValidator* baseValidator = 0;
|
|
const XMLCh* baseTypeName = getElementAttValue(contentElem, SchemaSymbols::fgATT_ITEMTYPE, DatatypeValidator::QName);
|
|
|
|
fAttributeCheck.checkAttributes(
|
|
contentElem, GeneralAttributeCheck::E_List, this, false, fNonXSAttList
|
|
);
|
|
|
|
const DOMElement* tempEl = XUtil::getNextSiblingElement(contentElem);
|
|
if (tempEl != 0) {
|
|
reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::SimpleTypeContentError, tempEl->getLocalName());
|
|
}
|
|
|
|
DOMElement* content = 0;
|
|
|
|
if (!baseTypeName || !*baseTypeName) { // must 'see' <simpleType>
|
|
|
|
content = checkContent(rootElem, XUtil::getFirstChildElement(contentElem), false);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(contentElem, fNonXSAttList);
|
|
}
|
|
if (fAnnotation)
|
|
{
|
|
if (janAnnot->isDataNull())
|
|
janAnnot->reset(fAnnotation);
|
|
else
|
|
janAnnot->get()->setNext(fAnnotation);
|
|
}
|
|
|
|
if (!content) {
|
|
|
|
reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::ExpectedSimpleTypeInList, typeName);
|
|
popCurrentTypeNameStack();
|
|
return 0;
|
|
}
|
|
|
|
if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_SIMPLETYPE)) {
|
|
baseValidator = checkForSimpleTypeValidator(content, SchemaSymbols::XSD_LIST);
|
|
}
|
|
else {
|
|
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::ListUnionRestrictionError, typeName);
|
|
popCurrentTypeNameStack();
|
|
return 0;
|
|
}
|
|
|
|
content = XUtil::getNextSiblingElement(content);
|
|
}
|
|
else { // base was provided - get proper validator
|
|
|
|
baseValidator = findDTValidator(contentElem, typeName, baseTypeName, SchemaSymbols::XSD_LIST);
|
|
content = checkContent(rootElem, XUtil::getFirstChildElement(contentElem), true);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(contentElem, fNonXSAttList);
|
|
}
|
|
if (fAnnotation)
|
|
{
|
|
if (janAnnot->isDataNull())
|
|
janAnnot->reset(fAnnotation);
|
|
else
|
|
janAnnot->get()->setNext(fAnnotation);
|
|
}
|
|
}
|
|
|
|
DatatypeValidator* newDV = 0;
|
|
|
|
if (baseValidator) {
|
|
|
|
if (!baseValidator->isAtomic()) {
|
|
reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::AtomicItemType, baseTypeName);
|
|
}
|
|
else {
|
|
|
|
// 'content' should be empty
|
|
// If an annotation was encountered we have already traversed it in
|
|
// checkContent in the case of a base provided (only allowed child is
|
|
// an annotation).
|
|
if (content != 0) { // report an error and continue
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::SimpleTypeDerivationByListError, typeName);
|
|
}
|
|
|
|
// create & register validator for "generated" type
|
|
try {
|
|
newDV = fDatatypeRegistry->createDatatypeValidator(
|
|
qualifiedName, baseValidator, 0, 0, true, finalSet, true, fGrammarPoolMemoryManager);
|
|
}
|
|
catch (const XMLException& excep) {
|
|
reportSchemaError(contentElem, excep);
|
|
}
|
|
catch(const OutOfMemoryException&)
|
|
{
|
|
throw;
|
|
}
|
|
catch(...) {
|
|
reportSchemaError(contentElem, XMLUni::fgXMLErrDomain,
|
|
XMLErrs::DatatypeValidatorCreationError, typeName);
|
|
}
|
|
}
|
|
}
|
|
|
|
popCurrentTypeNameStack();
|
|
return newDV;
|
|
}
|
|
|
|
/**
|
|
* Traverses Schema restriction simple type declaration.
|
|
*
|
|
* <restriction
|
|
* base = QName
|
|
* id = ID
|
|
* {any attributes with non-schema namespace . . .}>
|
|
* Content: (annotation?, (simpleType?,
|
|
* (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*))
|
|
* </restriction>
|
|
*
|
|
*/
|
|
DatatypeValidator*
|
|
TraverseSchema::traverseByRestriction(const DOMElement* const rootElem,
|
|
const DOMElement* const contentElem,
|
|
const XMLCh* const typeName,
|
|
const XMLCh* const qualifiedName,
|
|
const int finalSet,
|
|
Janitor<XSAnnotation>* const janAnnot) {
|
|
|
|
NamespaceScopeManager nsMgr(contentElem, fSchemaInfo, this);
|
|
|
|
DatatypeValidator* baseValidator = 0;
|
|
DatatypeValidator* newDV = 0;
|
|
const XMLCh* baseTypeName = getElementAttValue(contentElem, SchemaSymbols::fgATT_BASE, DatatypeValidator::QName);
|
|
|
|
fAttributeCheck.checkAttributes(
|
|
contentElem, GeneralAttributeCheck::E_Restriction, this, false, fNonXSAttList
|
|
);
|
|
|
|
const DOMElement* tempEl = XUtil::getNextSiblingElement(contentElem);
|
|
if (tempEl != 0) {
|
|
reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::SimpleTypeContentError, tempEl->getLocalName());
|
|
}
|
|
|
|
DOMElement* content = 0;
|
|
|
|
if (!baseTypeName || !*baseTypeName) { // must 'see' <simpleType>
|
|
|
|
content = checkContent(rootElem, XUtil::getFirstChildElement(contentElem), false);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(contentElem, fNonXSAttList);
|
|
}
|
|
if (fAnnotation)
|
|
{
|
|
if (janAnnot->isDataNull())
|
|
janAnnot->reset(fAnnotation);
|
|
else
|
|
janAnnot->get()->setNext(fAnnotation);
|
|
}
|
|
|
|
if (content == 0) {
|
|
|
|
reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::ExpectedSimpleTypeInRestriction);
|
|
popCurrentTypeNameStack();
|
|
return 0;
|
|
}
|
|
|
|
if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_SIMPLETYPE)) {
|
|
baseValidator = checkForSimpleTypeValidator(content);
|
|
}
|
|
else {
|
|
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::ListUnionRestrictionError, typeName);
|
|
popCurrentTypeNameStack();
|
|
return 0;
|
|
}
|
|
|
|
// Check for facets
|
|
content = XUtil::getNextSiblingElement(content);
|
|
}
|
|
else { // base was provided - get proper validator
|
|
|
|
baseValidator = findDTValidator(contentElem, typeName, baseTypeName, SchemaSymbols::XSD_RESTRICTION);
|
|
content = checkContent(rootElem, XUtil::getFirstChildElement(contentElem), true);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(contentElem, fNonXSAttList);
|
|
}
|
|
if (fAnnotation)
|
|
{
|
|
if (janAnnot->isDataNull())
|
|
janAnnot->reset(fAnnotation);
|
|
else
|
|
janAnnot->get()->setNext(fAnnotation);
|
|
}
|
|
}
|
|
|
|
if (baseValidator) {
|
|
|
|
// Get facets if any existing
|
|
typedef RefHashTableOf<KVStringPair> KVRefHash;
|
|
Janitor<KVRefHash> janFacets(0);
|
|
//RefHashTableOf<KVStringPair>* facets = 0;
|
|
typedef RefArrayVectorOf<XMLCh> XMLChRefArray;
|
|
Janitor<XMLChRefArray> enums(0);
|
|
//RefArrayVectorOf<XMLCh>* enums = 0;
|
|
XMLBuffer pattern(128, fGrammarPoolMemoryManager);
|
|
Janitor<XSAnnotation> janEnumAnnot(0);
|
|
Janitor<XSAnnotation> janPatternAnnot(0);
|
|
XMLCh fixedFlagStr[16];
|
|
unsigned int fixedFlag = 0;
|
|
unsigned short scope = 0;
|
|
bool isFirstPattern = true;
|
|
bool sawPattern = false;
|
|
|
|
|
|
while (content != 0) {
|
|
|
|
if (content->getNodeType() == DOMNode::ELEMENT_NODE) {
|
|
|
|
NamespaceScopeManager nsMgr(content, fSchemaInfo, this);
|
|
|
|
const XMLCh* facetName = content->getLocalName();
|
|
|
|
bool bContinue=false; // workaround for Borland bug with 'continue' in 'catch'
|
|
try {
|
|
scope = fAttributeCheck.getFacetId(facetName, fMemoryManager);
|
|
}
|
|
catch(const OutOfMemoryException&)
|
|
{
|
|
throw;
|
|
}
|
|
catch (...) {
|
|
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::InvalidFacetName, facetName);
|
|
content = XUtil::getNextSiblingElement(content);
|
|
bContinue=true;
|
|
}
|
|
if(bContinue)
|
|
continue;
|
|
|
|
fAttributeCheck.checkAttributes(
|
|
content, scope, this, false, fNonXSAttList
|
|
);
|
|
if (checkContent(rootElem, XUtil::getFirstChildElement(content), true) != 0)
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected);
|
|
|
|
const XMLCh* attValue = content->getAttribute(SchemaSymbols::fgATT_VALUE);
|
|
if (janFacets.get() == 0) {
|
|
janFacets.reset(new (fGrammarPoolMemoryManager) RefHashTableOf<KVStringPair>(29, true, fGrammarPoolMemoryManager));
|
|
|
|
}
|
|
|
|
if (XMLString::equals(facetName, SchemaSymbols::fgELT_ENUMERATION)) {
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(content, fNonXSAttList);
|
|
}
|
|
if (fAnnotation) {
|
|
if (janEnumAnnot.isDataNull())
|
|
janEnumAnnot.reset(fAnnotation);
|
|
else
|
|
janEnumAnnot.get()->setNext(fAnnotation);
|
|
}
|
|
|
|
// REVISIT
|
|
// if validator is a notation datatype validator, we need
|
|
// to get the qualified name first before adding it to the
|
|
// enum buffer
|
|
if (!enums.get()) {
|
|
enums.reset(new (fGrammarPoolMemoryManager) RefArrayVectorOf<XMLCh>(8, true, fGrammarPoolMemoryManager));
|
|
}
|
|
|
|
if (baseValidator->getType() == DatatypeValidator::NOTATION) {
|
|
|
|
const XMLCh* localPart = getLocalPart(attValue);
|
|
const XMLCh* prefix = getPrefix(attValue);
|
|
const XMLCh* uriStr = (prefix && *prefix) ? resolvePrefixToURI(content, prefix) : fTargetNSURIString;
|
|
unsigned int uriId = fURIStringPool->addOrFind(uriStr);
|
|
|
|
if (!fNotationRegistry->containsKey(localPart, uriId)) {
|
|
traverseNotationDecl(content, localPart, uriStr);
|
|
}
|
|
|
|
if (uriStr && *uriStr) {
|
|
fBuffer.set(uriStr);
|
|
fBuffer.append(chColon);
|
|
fBuffer.append(localPart);
|
|
enums.get()->addElement(XMLString::replicate(fBuffer.getRawBuffer(), fGrammarPoolMemoryManager));
|
|
}
|
|
else {
|
|
enums.get()->addElement(XMLString::replicate(localPart, fGrammarPoolMemoryManager));
|
|
}
|
|
|
|
}
|
|
else if (baseValidator->getType() == DatatypeValidator::QName) {
|
|
// We need the URI string for the prefix to determine
|
|
// if that matches the value in the instance document.
|
|
// Code was just comparing the string of prefix:localname
|
|
// and if the schema and instance document had different
|
|
// prefixes with the same URI string then we were giving an error.
|
|
const XMLCh* prefix = getPrefix(attValue);
|
|
const XMLCh* uriStr = (prefix && *prefix) ? resolvePrefixToURI(content, prefix) : fTargetNSURIString;
|
|
|
|
enums.get()->addElement(XMLString::replicate(attValue, fGrammarPoolMemoryManager));
|
|
enums.get()->addElement(XMLString::replicate(uriStr, fGrammarPoolMemoryManager));
|
|
}
|
|
else {
|
|
enums.get()->addElement(XMLString::replicate(attValue, fGrammarPoolMemoryManager));
|
|
}
|
|
}
|
|
else if (XMLString::equals(facetName, SchemaSymbols::fgELT_PATTERN)) {
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(content, fNonXSAttList);
|
|
}
|
|
if (fAnnotation) {
|
|
if (janPatternAnnot.isDataNull())
|
|
janPatternAnnot.reset(fAnnotation);
|
|
else
|
|
janPatternAnnot.get()->setNext(fAnnotation);
|
|
}
|
|
sawPattern = true;
|
|
if (isFirstPattern) { // fBuffer.isEmpty() - overhead call
|
|
|
|
isFirstPattern = false;
|
|
pattern.set(attValue);
|
|
}
|
|
else { //datatypes: 5.2.4 pattern
|
|
|
|
pattern.append(chPipe);
|
|
pattern.append(attValue);
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (janFacets.get()->containsKey(facetName)) {
|
|
|
|
if (fAnnotation)
|
|
delete fAnnotation;
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateFacet, facetName);
|
|
}
|
|
else {
|
|
|
|
if (XMLString::equals(facetName, SchemaSymbols::fgELT_WHITESPACE)
|
|
&& baseValidator->getType() != DatatypeValidator::String
|
|
&& !XMLString::equals(attValue, SchemaSymbols::fgWS_COLLAPSE)) {
|
|
|
|
if (fAnnotation)
|
|
delete fAnnotation;
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::WS_CollapseExpected, attValue);
|
|
}
|
|
else {
|
|
|
|
const XMLCh* facetStr = fStringPool->getValueForId(fStringPool->addOrFind(facetName));
|
|
KVStringPair* kv = new (fGrammarPoolMemoryManager) KVStringPair(facetStr, attValue, fGrammarPoolMemoryManager);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(content, fNonXSAttList);
|
|
}
|
|
if (fAnnotation)
|
|
fSchemaGrammar->putAnnotation(kv, fAnnotation);
|
|
|
|
janFacets.get()->put((void*) facetStr, kv);
|
|
checkFixedFacet(content, facetStr, baseValidator, fixedFlag);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
content = XUtil::getNextSiblingElement(content);
|
|
} // end while
|
|
|
|
if (sawPattern) {
|
|
|
|
KVStringPair* kv = new (fGrammarPoolMemoryManager) KVStringPair(SchemaSymbols::fgELT_PATTERN, pattern.getRawBuffer(), pattern.getLen(), fGrammarPoolMemoryManager);
|
|
if (!janPatternAnnot.isDataNull())
|
|
fSchemaGrammar->putAnnotation(kv, janPatternAnnot.release());
|
|
janFacets.get()->put((void*) SchemaSymbols::fgELT_PATTERN, kv);
|
|
}
|
|
|
|
if (fixedFlag) {
|
|
|
|
XMLString::binToText(fixedFlag, fixedFlagStr, 15, 10, fGrammarPoolMemoryManager);
|
|
janFacets.get()->put((void*) SchemaSymbols::fgATT_FIXED,
|
|
new (fGrammarPoolMemoryManager) KVStringPair(SchemaSymbols::fgATT_FIXED, fixedFlagStr, fGrammarPoolMemoryManager));
|
|
}
|
|
|
|
if (enums.get() && !janEnumAnnot.isDataNull())
|
|
fSchemaGrammar->putAnnotation(enums.get(), janEnumAnnot.release());
|
|
|
|
try {
|
|
newDV = fDatatypeRegistry->createDatatypeValidator(qualifiedName, baseValidator, janFacets.release(), enums.release(), false, finalSet, true, fGrammarPoolMemoryManager);
|
|
}
|
|
catch (const XMLException& excep) {
|
|
reportSchemaError(contentElem, excep);
|
|
}
|
|
catch(const OutOfMemoryException&)
|
|
{
|
|
throw;
|
|
}
|
|
catch(...) {
|
|
reportSchemaError(contentElem, XMLUni::fgXMLErrDomain,
|
|
XMLErrs::DatatypeValidatorCreationError, typeName);
|
|
}
|
|
}
|
|
popCurrentTypeNameStack();
|
|
return newDV;
|
|
}
|
|
|
|
/**
|
|
* Traverses Schema union simple type declaration.
|
|
*
|
|
* <union
|
|
* id = ID
|
|
* memberTypes = List of QName
|
|
* {any attributes with non-schema namespace . . .}>
|
|
* Content: (annotation?, simpleType*)
|
|
* </union>
|
|
*
|
|
*/
|
|
DatatypeValidator*
|
|
TraverseSchema::traverseByUnion(const DOMElement* const rootElem,
|
|
const DOMElement* const contentElem,
|
|
const XMLCh* const typeName,
|
|
const XMLCh* const qualifiedName,
|
|
const int finalSet,
|
|
int baseRefContext,
|
|
Janitor<XSAnnotation>* const janAnnot) {
|
|
|
|
NamespaceScopeManager nsMgr(contentElem, fSchemaInfo, this);
|
|
|
|
fAttributeCheck.checkAttributes(
|
|
contentElem, GeneralAttributeCheck::E_Union, this, false, fNonXSAttList
|
|
);
|
|
|
|
const DOMElement* tempEl = XUtil::getNextSiblingElement(contentElem);
|
|
if (tempEl != 0) {
|
|
reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::SimpleTypeContentError, tempEl->getLocalName());
|
|
}
|
|
|
|
const XMLCh* baseTypeName = getElementAttValue(contentElem, SchemaSymbols::fgATT_MEMBERTYPES);
|
|
DatatypeValidator* baseValidator = 0;
|
|
RefVectorOf<DatatypeValidator>* validators = new (fGrammarPoolMemoryManager) RefVectorOf<DatatypeValidator>(4, false, fGrammarPoolMemoryManager);
|
|
Janitor<RefVectorOf<DatatypeValidator> > janValidators(validators);
|
|
DOMElement* content = 0;
|
|
|
|
if (baseTypeName && *baseTypeName) { //base was provided - get proper validator.
|
|
|
|
XMLStringTokenizer unionMembers(baseTypeName, fGrammarPoolMemoryManager);
|
|
int tokCount = unionMembers.countTokens();
|
|
|
|
for (int i = 0; i < tokCount; i++) {
|
|
|
|
const XMLCh* memberTypeName = unionMembers.nextToken();
|
|
|
|
baseValidator = findDTValidator(contentElem, typeName, memberTypeName, SchemaSymbols::XSD_UNION);
|
|
|
|
if (baseValidator == 0) {
|
|
|
|
popCurrentTypeNameStack();
|
|
return 0;
|
|
}
|
|
|
|
validators->addElement(baseValidator);
|
|
}
|
|
|
|
content = checkContent(rootElem, XUtil::getFirstChildElement(contentElem), true);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(contentElem, fNonXSAttList);
|
|
}
|
|
if (fAnnotation)
|
|
{
|
|
if (janAnnot->isDataNull())
|
|
janAnnot->reset(fAnnotation);
|
|
else
|
|
janAnnot->get()->setNext(fAnnotation);
|
|
}
|
|
}
|
|
else { // must 'see' <simpleType>
|
|
|
|
content = checkContent(rootElem, XUtil::getFirstChildElement(contentElem), false);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(contentElem, fNonXSAttList);
|
|
}
|
|
if (fAnnotation)
|
|
{
|
|
if (janAnnot->isDataNull())
|
|
janAnnot->reset(fAnnotation);
|
|
else
|
|
janAnnot->get()->setNext(fAnnotation);
|
|
}
|
|
|
|
if (content == 0) {
|
|
|
|
reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::ExpectedSimpleTypeInUnion, typeName);
|
|
popCurrentTypeNameStack();
|
|
return 0;
|
|
}
|
|
|
|
if (!XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_SIMPLETYPE)) {
|
|
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::ListUnionRestrictionError, typeName);
|
|
popCurrentTypeNameStack();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// process union content of simpleType children if any
|
|
while (content != 0) {
|
|
|
|
if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_SIMPLETYPE)) {
|
|
|
|
baseValidator = checkForSimpleTypeValidator(content, baseRefContext | SchemaSymbols::XSD_UNION);
|
|
|
|
if (baseValidator == 0) {
|
|
|
|
popCurrentTypeNameStack();
|
|
return 0;
|
|
}
|
|
|
|
validators->addElement(baseValidator);
|
|
}
|
|
else {
|
|
// REVISIT - should we break. For now, we will continue and move to
|
|
// the next sibling
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::ListUnionRestrictionError, typeName);
|
|
}
|
|
|
|
content = XUtil::getNextSiblingElement(content);
|
|
} // end while
|
|
|
|
DatatypeValidator* newDV = 0;
|
|
janValidators.orphan();
|
|
|
|
try {
|
|
newDV = fDatatypeRegistry->createDatatypeValidator(qualifiedName, validators, finalSet, true, fGrammarPoolMemoryManager);
|
|
}
|
|
catch (const XMLException& excep) {
|
|
reportSchemaError(contentElem, excep);
|
|
}
|
|
catch(const OutOfMemoryException&)
|
|
{
|
|
throw;
|
|
}
|
|
catch(...) {
|
|
reportSchemaError(contentElem, XMLUni::fgXMLErrDomain,
|
|
XMLErrs::DatatypeValidatorCreationError, typeName);
|
|
}
|
|
|
|
popCurrentTypeNameStack();
|
|
return newDV;
|
|
}
|
|
|
|
|
|
/**
|
|
* Traverse SimpleContent Declaration
|
|
*
|
|
* <simpleContent
|
|
* id = ID
|
|
* {any attributes with non-schema namespace...}>
|
|
*
|
|
* Content: (annotation? , (restriction | extension))
|
|
* </simpleContent>
|
|
*
|
|
* <restriction
|
|
* base = QNAME
|
|
* id = ID
|
|
* {any attributes with non-schema namespace...}>
|
|
*
|
|
* Content: (annotation?, (simpleType?, (minExclusive | minInclusive
|
|
* | maxExclusive | maxInclusive | totalDigits | fractionDigits
|
|
* | length | minLength | maxLength | enumeration | pattern
|
|
* | whiteSpace)*)?, ((attribute | attributeGroup)* , anyAttribute?))
|
|
* </restriction>
|
|
*
|
|
* <extension
|
|
* base = QNAME
|
|
* id = ID
|
|
* {any attributes with non-schema namespace...}>
|
|
* Content: (annotation? , ((attribute | attributeGroup)* , anyAttribute?))
|
|
* </extension>
|
|
*
|
|
*/
|
|
void TraverseSchema::traverseSimpleContentDecl(const XMLCh* const typeName,
|
|
const XMLCh* const qualifiedName,
|
|
const DOMElement* const contentDecl,
|
|
ComplexTypeInfo* const typeInfo,
|
|
Janitor<XSAnnotation>* const janAnnot)
|
|
{
|
|
NamespaceScopeManager nsMgr(contentDecl, fSchemaInfo, this);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check Attributes
|
|
// -----------------------------------------------------------------------
|
|
bool preProcessFlag = typeInfo->getPreprocessed();
|
|
|
|
if (!preProcessFlag) {
|
|
fAttributeCheck.checkAttributes(
|
|
contentDecl, GeneralAttributeCheck::E_SimpleContent
|
|
, this, false, fNonXSAttList
|
|
);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Set the content type to be simple, and initialize content spec handle
|
|
// -----------------------------------------------------------------------
|
|
typeInfo->setContentType(SchemaElementDecl::Simple);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Process annotation if any
|
|
// -----------------------------------------------------------------------
|
|
DOMElement* simpleContent = checkContent(contentDecl, XUtil::getFirstChildElement(contentDecl), false, !preProcessFlag);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(contentDecl, fNonXSAttList);
|
|
}
|
|
if (fAnnotation)
|
|
{
|
|
if (janAnnot->isDataNull())
|
|
janAnnot->reset(fAnnotation);
|
|
else
|
|
janAnnot->get()->setNext(fAnnotation);
|
|
}
|
|
|
|
// If there are no children, return
|
|
if (simpleContent == 0) {
|
|
|
|
reportSchemaError(contentDecl, XMLUni::fgXMLErrDomain, XMLErrs::EmptySimpleTypeContent);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
|
|
NamespaceScopeManager nsMgr2(simpleContent, fSchemaInfo, this);
|
|
// -----------------------------------------------------------------------
|
|
// The content should be either "restriction" or "extension"
|
|
// -----------------------------------------------------------------------
|
|
if (!preProcessFlag) {
|
|
const XMLCh* const contentName = simpleContent->getLocalName();
|
|
|
|
if (XMLString::equals(contentName, SchemaSymbols::fgATTVAL_RESTRICTION)) {
|
|
|
|
fAttributeCheck.checkAttributes(
|
|
simpleContent, GeneralAttributeCheck::E_Restriction
|
|
, this, false, fNonXSAttList
|
|
);
|
|
typeInfo->setDerivedBy(SchemaSymbols::XSD_RESTRICTION);
|
|
}
|
|
else if (XMLString::equals(contentName, SchemaSymbols::fgATTVAL_EXTENSION)) {
|
|
|
|
fAttributeCheck.checkAttributes(
|
|
simpleContent, GeneralAttributeCheck::E_Extension
|
|
, this, false, fNonXSAttList
|
|
);
|
|
typeInfo->setDerivedBy(SchemaSymbols::XSD_EXTENSION);
|
|
}
|
|
else {
|
|
reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidSimpleContent);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
}
|
|
|
|
//Skip over any annotations in the restriction or extension elements
|
|
DOMElement* content = checkContent(simpleContent, XUtil::getFirstChildElement(simpleContent), true, !preProcessFlag);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(simpleContent, fNonXSAttList);
|
|
}
|
|
if (fAnnotation)
|
|
{
|
|
if (janAnnot->isDataNull())
|
|
janAnnot->reset(fAnnotation);
|
|
else
|
|
janAnnot->get()->setNext(fAnnotation);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Handle the base type name
|
|
// -----------------------------------------------------------------------
|
|
const XMLCh* baseName = getElementAttValue(simpleContent, SchemaSymbols::fgATT_BASE, DatatypeValidator::QName);
|
|
|
|
if (!baseName || !*baseName) {
|
|
|
|
reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::UnspecifiedBase);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
|
|
const XMLCh* prefix = getPrefix(baseName);
|
|
const XMLCh* localPart = getLocalPart(baseName);
|
|
const XMLCh* uri = resolvePrefixToURI(simpleContent, prefix);
|
|
|
|
// check for 'anyType'
|
|
if (XMLString::equals(uri, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)
|
|
&& XMLString::equals(localPart, SchemaSymbols::fgATTVAL_ANYTYPE)) {
|
|
|
|
reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidSimpleContentBase, baseName);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
|
|
processBaseTypeInfo(simpleContent, baseName, localPart, uri, typeInfo);
|
|
|
|
ComplexTypeInfo* baseTypeInfo = typeInfo->getBaseComplexTypeInfo();
|
|
DatatypeValidator* baseValidator = typeInfo->getBaseDatatypeValidator();
|
|
|
|
if (baseValidator != 0 && baseTypeInfo == 0) {
|
|
|
|
// check that the simpleType does not preclude derivation by extension
|
|
if ((baseValidator->getFinalSet() & SchemaSymbols::XSD_EXTENSION) == typeInfo->getDerivedBy()) {
|
|
|
|
reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::DisallowedSimpleTypeExtension,
|
|
baseName, typeName);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
|
|
//Schema Spec: 5.11: Complex Type Definition Properties Correct: 2
|
|
if (typeInfo->getDerivedBy() == SchemaSymbols::XSD_RESTRICTION) {
|
|
|
|
reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidComplexTypeBase, baseName);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
}
|
|
|
|
// check that the base isn't a complex type with complex content
|
|
// and that derivation method is not included in 'final'
|
|
bool simpleTypeRequired = false;
|
|
|
|
if (baseTypeInfo) {
|
|
|
|
if (baseTypeInfo->getContentType() != SchemaElementDecl::Simple) {
|
|
|
|
// Schema Errata: E1-27
|
|
if (typeInfo->getDerivedBy() == SchemaSymbols::XSD_RESTRICTION
|
|
&& ((baseTypeInfo->getContentType() == SchemaElementDecl::Mixed_Simple
|
|
|| baseTypeInfo->getContentType() == SchemaElementDecl::Mixed_Complex)
|
|
&& emptiableParticle(baseTypeInfo->getContentSpec()))) {
|
|
simpleTypeRequired = true;
|
|
}
|
|
else {
|
|
reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidSimpleContentBase, baseName);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
}
|
|
|
|
if ((baseTypeInfo->getFinalSet() & typeInfo->getDerivedBy()) != 0) {
|
|
reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::ForbiddenDerivation, baseName);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Process the content of the derivation
|
|
// -----------------------------------------------------------------------
|
|
if (typeInfo->getDerivedBy() == SchemaSymbols::XSD_RESTRICTION) {
|
|
|
|
if(baseTypeInfo)
|
|
typeInfo->setBaseDatatypeValidator(baseTypeInfo->getDatatypeValidator());
|
|
|
|
if (content != 0) {
|
|
|
|
// ---------------------------------------------------------------
|
|
// There may be a simple type definition in the restriction
|
|
// element. The data type validator will be based on it, if
|
|
// specified
|
|
// ---------------------------------------------------------------
|
|
if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_SIMPLETYPE)) {
|
|
|
|
DatatypeValidator* simpleTypeDV = traverseSimpleTypeDecl(content, false);
|
|
|
|
if (simpleTypeDV) {
|
|
|
|
// Check that the simpleType validator is validly derived
|
|
// from base
|
|
DatatypeValidator* baseDV = typeInfo->getBaseDatatypeValidator();
|
|
|
|
if (baseDV && !baseDV->isSubstitutableBy(simpleTypeDV)) {
|
|
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::InvalidContentRestriction);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
|
|
typeInfo->setBaseDatatypeValidator(simpleTypeDV);
|
|
content = XUtil::getNextSiblingElement(content);
|
|
}
|
|
else {
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
}
|
|
// Schema Errata E1-27
|
|
// Complex Type Definition Restriction OK: 2.2
|
|
else if (simpleTypeRequired) {
|
|
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::CT_SimpleTypeChildRequired);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Build up the facet info
|
|
// ---------------------------------------------------------------
|
|
RefHashTableOf<KVStringPair>* facets = 0;
|
|
RefArrayVectorOf<XMLCh>* enums = 0;
|
|
XMLBuffer pattern(128, fGrammarPoolMemoryManager);
|
|
XMLCh fixedFlagStr[16];
|
|
unsigned int fixedFlag = 0;
|
|
unsigned short scope = 0;
|
|
bool isFirstPattern = true;
|
|
|
|
while (content != 0) {
|
|
|
|
const XMLCh* facetName = content->getLocalName();
|
|
|
|
bool bDoBreak=false; // workaround for Borland bug with 'break' in 'catch'
|
|
// if not a valid facet, break from the loop
|
|
try {
|
|
scope = fAttributeCheck.getFacetId(facetName, fMemoryManager);
|
|
}
|
|
catch(const OutOfMemoryException&)
|
|
{
|
|
throw;
|
|
}
|
|
catch(...) {
|
|
bDoBreak=true;
|
|
}
|
|
if(bDoBreak)
|
|
break;
|
|
|
|
if (content->getNodeType() == DOMNode::ELEMENT_NODE) {
|
|
|
|
fAttributeCheck.checkAttributes(content, scope, this);
|
|
|
|
const XMLCh* attValue = content->getAttribute(SchemaSymbols::fgATT_VALUE);
|
|
|
|
if (facets == 0) {
|
|
facets = new (fGrammarPoolMemoryManager) RefHashTableOf<KVStringPair>(29, true, fGrammarPoolMemoryManager);
|
|
}
|
|
|
|
if (XMLString::equals(facetName, SchemaSymbols::fgELT_ENUMERATION)) {
|
|
|
|
if (!enums) {
|
|
enums = new (fGrammarPoolMemoryManager) RefArrayVectorOf<XMLCh>(8, true, fGrammarPoolMemoryManager);
|
|
}
|
|
|
|
enums->addElement(XMLString::replicate(attValue, fGrammarPoolMemoryManager));
|
|
}
|
|
else if (XMLString::equals(facetName, SchemaSymbols::fgELT_PATTERN)) {
|
|
|
|
if (isFirstPattern) { // fBuffer.isEmpty() - overhead call
|
|
|
|
isFirstPattern = false;
|
|
pattern.set(attValue);
|
|
}
|
|
else { //datatypes: 5.2.4 pattern
|
|
|
|
pattern.append(chPipe);
|
|
pattern.append(attValue);
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (facets->containsKey(facetName)) {
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateFacet, facetName);
|
|
}
|
|
else {
|
|
|
|
const XMLCh* facetNameStr =
|
|
fStringPool->getValueForId(fStringPool->addOrFind(facetName));
|
|
|
|
facets->put((void*) facetNameStr, new (fGrammarPoolMemoryManager) KVStringPair(facetNameStr, attValue, fGrammarPoolMemoryManager));
|
|
checkFixedFacet(content, facetNameStr, typeInfo->getBaseDatatypeValidator(), fixedFlag);
|
|
}
|
|
}
|
|
}
|
|
|
|
content = XUtil::getNextSiblingElement(content);
|
|
}
|
|
|
|
if (facets) {
|
|
|
|
if (!pattern.isEmpty()) {
|
|
facets->put
|
|
(
|
|
(void*) SchemaSymbols::fgELT_PATTERN,
|
|
new (fGrammarPoolMemoryManager) KVStringPair
|
|
(
|
|
SchemaSymbols::fgELT_PATTERN
|
|
, pattern.getRawBuffer()
|
|
, pattern.getLen()
|
|
, fGrammarPoolMemoryManager
|
|
)
|
|
);
|
|
}
|
|
|
|
if (fixedFlag) {
|
|
|
|
XMLString::binToText(fixedFlag, fixedFlagStr, 15, 10, fGrammarPoolMemoryManager);
|
|
facets->put((void*) SchemaSymbols::fgATT_FIXED,
|
|
new (fGrammarPoolMemoryManager) KVStringPair(SchemaSymbols::fgATT_FIXED, fixedFlagStr, fGrammarPoolMemoryManager));
|
|
}
|
|
|
|
try {
|
|
|
|
DatatypeValidator* simpleDV =
|
|
fDatatypeRegistry->createDatatypeValidator
|
|
(
|
|
qualifiedName,
|
|
typeInfo->getBaseDatatypeValidator(),
|
|
facets, enums, false, 0, true, fGrammarPoolMemoryManager
|
|
);
|
|
simpleDV->setAnonymous();
|
|
typeInfo->setDatatypeValidator(simpleDV);
|
|
}
|
|
catch (const XMLException& excep) {
|
|
reportSchemaError(simpleContent, excep);
|
|
}
|
|
catch(const OutOfMemoryException&)
|
|
{
|
|
throw;
|
|
}
|
|
catch(...) {
|
|
reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::DatatypeValidatorCreationError, typeName);
|
|
}
|
|
}
|
|
else {
|
|
typeInfo->setDatatypeValidator(typeInfo->getBaseDatatypeValidator());
|
|
}
|
|
}
|
|
else {
|
|
|
|
// Schema Errata E1-27
|
|
// Complex Type Definition Restriction OK: 2.2
|
|
if (simpleTypeRequired) {
|
|
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::CT_SimpleTypeChildRequired);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
|
|
typeInfo->setDatatypeValidator(typeInfo->getBaseDatatypeValidator());
|
|
}
|
|
} // end RESTRICTION
|
|
else { // EXTENSION
|
|
|
|
ComplexTypeInfo* baseTypeInfo = typeInfo->getBaseComplexTypeInfo();
|
|
|
|
if (baseTypeInfo!= 0) {
|
|
|
|
typeInfo->setBaseDatatypeValidator(baseTypeInfo->getDatatypeValidator());
|
|
}
|
|
|
|
typeInfo->setDatatypeValidator(typeInfo->getBaseDatatypeValidator());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Process attributes if any
|
|
// -----------------------------------------------------------------------
|
|
processAttributes(simpleContent, content, typeInfo);
|
|
|
|
if (XUtil::getNextSiblingElement(simpleContent) != 0) {
|
|
reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInSimpleContent);
|
|
}
|
|
|
|
} // End of function traverseSimpleContentDecl
|
|
|
|
/**
|
|
* Traverse complexContent Declaration
|
|
*
|
|
* <complexContent
|
|
* id = ID
|
|
* mixed = boolean
|
|
* {any attributes with non-schema namespace...}>
|
|
*
|
|
* Content: (annotation? , (restriction | extension))
|
|
* </complexContent>
|
|
*
|
|
* <restriction
|
|
* base = QNAME
|
|
* id = ID
|
|
* {any attributes with non-schema namespace...}>
|
|
*
|
|
* Content: (annotation? , (group | all | choice | sequence)?,
|
|
* ((attribute | attributeGroup)* , anyAttribute?))
|
|
* </restriction>
|
|
*
|
|
* <extension
|
|
* base = QNAME
|
|
* id = ID
|
|
* {any attributes with non-schema namespace...}>
|
|
* Content: (annotation? , (group | all | choice | sequence)?,
|
|
* ((attribute | attributeGroup)* , anyAttribute?))
|
|
* </extension>
|
|
*/
|
|
void TraverseSchema::traverseComplexContentDecl(const XMLCh* const typeName,
|
|
const DOMElement* const contentDecl,
|
|
ComplexTypeInfo* const typeInfo,
|
|
const bool isMixed,
|
|
Janitor<XSAnnotation>* const janAnnot)
|
|
{
|
|
NamespaceScopeManager nsMgr(contentDecl, fSchemaInfo, this);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check attributes
|
|
// -----------------------------------------------------------------------
|
|
bool preProcessFlag = typeInfo->getPreprocessed();
|
|
|
|
if (!preProcessFlag) {
|
|
fAttributeCheck.checkAttributes(
|
|
contentDecl, GeneralAttributeCheck::E_ComplexContent
|
|
, this, false, fNonXSAttList
|
|
);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Determine whether the content is mixed, or element-only
|
|
// Setting here overrides any setting on the complex type decl
|
|
// -----------------------------------------------------------------------
|
|
const XMLCh* const mixed = getElementAttValue(contentDecl, SchemaSymbols::fgATT_MIXED, DatatypeValidator::Boolean);
|
|
bool mixedContent = isMixed;
|
|
|
|
if (mixed) {
|
|
if (XMLString::equals(mixed, SchemaSymbols::fgATTVAL_TRUE)
|
|
|| XMLString::equals(mixed, fgValueOne)) {
|
|
mixedContent = true;
|
|
}
|
|
else if (XMLString::equals(mixed, SchemaSymbols::fgATTVAL_FALSE)
|
|
|| XMLString::equals(mixed, fgValueZero)) {
|
|
mixedContent = false;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Since the type must have complex content, set the simple type validators
|
|
// to null
|
|
// -----------------------------------------------------------------------
|
|
typeInfo->setDatatypeValidator(0);
|
|
typeInfo->setBaseDatatypeValidator(0);
|
|
|
|
DOMElement* complexContent = checkContent(contentDecl,XUtil::getFirstChildElement(contentDecl),false, !preProcessFlag);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(contentDecl, fNonXSAttList);
|
|
}
|
|
if (fAnnotation)
|
|
{
|
|
if (janAnnot->isDataNull())
|
|
janAnnot->reset(fAnnotation);
|
|
else
|
|
janAnnot->get()->setNext(fAnnotation);
|
|
}
|
|
|
|
// If there are no children, return
|
|
if (complexContent == 0) {
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
|
|
NamespaceScopeManager nsMgr2(complexContent, fSchemaInfo, this);
|
|
// -----------------------------------------------------------------------
|
|
// The content should be either "restriction" or "extension"
|
|
// -----------------------------------------------------------------------
|
|
const XMLCh* const complexContentName = complexContent->getLocalName();
|
|
|
|
if (XMLString::equals(complexContentName, SchemaSymbols::fgELT_RESTRICTION)) {
|
|
typeInfo->setDerivedBy(SchemaSymbols::XSD_RESTRICTION);
|
|
}
|
|
else if (XMLString::equals(complexContentName, SchemaSymbols::fgELT_EXTENSION)) {
|
|
typeInfo->setDerivedBy(SchemaSymbols::XSD_EXTENSION);
|
|
}
|
|
else {
|
|
|
|
reportSchemaError(complexContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidComplexContent);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Handle the base type name
|
|
// -----------------------------------------------------------------------
|
|
const XMLCh* baseName = getElementAttValue(complexContent, SchemaSymbols::fgATT_BASE, DatatypeValidator::QName);
|
|
|
|
if (!baseName || !*baseName) {
|
|
|
|
reportSchemaError(complexContent, XMLUni::fgXMLErrDomain, XMLErrs::UnspecifiedBase);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
|
|
const XMLCh* prefix = getPrefix(baseName);
|
|
const XMLCh* localPart = getLocalPart(baseName);
|
|
const XMLCh* uri = resolvePrefixToURI(complexContent, prefix);
|
|
bool isBaseAnyType = false;
|
|
|
|
// -------------------------------------------------------------
|
|
// check if the base is "anyType"
|
|
// -------------------------------------------------------------
|
|
if (XMLString::equals(uri, SchemaSymbols::fgURI_SCHEMAFORSCHEMA) &&
|
|
XMLString::equals(localPart, SchemaSymbols::fgATTVAL_ANYTYPE)) {
|
|
isBaseAnyType = true;
|
|
}
|
|
else {
|
|
|
|
processBaseTypeInfo(complexContent, baseName, localPart, uri, typeInfo);
|
|
|
|
//Check that the base is a complex type
|
|
if (typeInfo->getBaseComplexTypeInfo() == 0) {
|
|
|
|
reportSchemaError(complexContent, XMLUni::fgXMLErrDomain, XMLErrs::BaseNotComplexType);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
}
|
|
|
|
if (fCurrentGroupInfo) // defer processing until later
|
|
throw TraverseSchema::RecursingElement;
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Process the content of the derivation
|
|
// -----------------------------------------------------------------------
|
|
//Skip over any annotations in the restriction or extension elements
|
|
DOMElement* content = checkContent(complexContent, XUtil::getFirstChildElement(complexContent), true);
|
|
if (fAnnotation)
|
|
{
|
|
if (janAnnot->isDataNull())
|
|
janAnnot->reset(fAnnotation);
|
|
else
|
|
janAnnot->get()->setNext(fAnnotation);
|
|
}
|
|
|
|
processComplexContent(complexContent, typeName, content, typeInfo, localPart,
|
|
mixedContent, isBaseAnyType);
|
|
|
|
if (XUtil::getNextSiblingElement(complexContent) != 0) {
|
|
reportSchemaError(complexContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInComplexContent);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* <anyAttribute
|
|
* id = ID
|
|
* namespace = ((##any | ##other) | list of (anyURI | (##targetNamespace | ##local)))>
|
|
* processContents = (lax | skip | strict) : strict
|
|
* Content: (annotation?)
|
|
* </anyAttribute>
|
|
*/
|
|
SchemaAttDef* TraverseSchema::traverseAnyAttribute(const DOMElement* const elem) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check Attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
elem, GeneralAttributeCheck::E_AnyAttribute, this, false, fNonXSAttList
|
|
);
|
|
|
|
// ------------------------------------------------------------------
|
|
// First, handle any ANNOTATION declaration
|
|
// ------------------------------------------------------------------
|
|
if (checkContent(elem, XUtil::getFirstChildElement(elem), true) != 0) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AnyAttributeContentError);
|
|
}
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
}
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
// ------------------------------------------------------------------
|
|
// Get attributes
|
|
// ------------------------------------------------------------------
|
|
const XMLCh* const processContents = getElementAttValue(elem, SchemaSymbols::fgATT_PROCESSCONTENTS);
|
|
const XMLCh* const nameSpace = getElementAttValue(elem, SchemaSymbols::fgATT_NAMESPACE);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Set default att type based on 'processContents' value
|
|
// ------------------------------------------------------------------
|
|
XMLAttDef::DefAttTypes attDefType = XMLAttDef::ProcessContents_Strict;
|
|
|
|
if ((!processContents || !*processContents)
|
|
|| XMLString::equals(processContents, SchemaSymbols::fgATTVAL_STRICT)) {
|
|
// Do nothing - defaulted already
|
|
}
|
|
else if (XMLString::equals(processContents, SchemaSymbols::fgATTVAL_SKIP)) {
|
|
attDefType = XMLAttDef::ProcessContents_Skip;
|
|
}
|
|
else if (XMLString::equals(processContents, SchemaSymbols::fgATTVAL_LAX)) {
|
|
attDefType = XMLAttDef::ProcessContents_Lax;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Process 'namespace' attribute
|
|
// ------------------------------------------------------------------
|
|
int uriIndex = fEmptyNamespaceURI;
|
|
XMLAttDef::AttTypes attType = XMLAttDef::Any_Any;
|
|
ValueVectorOf<unsigned int> namespaceList(8, fGrammarPoolMemoryManager);
|
|
|
|
if ((!nameSpace || !*nameSpace)
|
|
|| XMLString::equals(nameSpace, SchemaSymbols::fgATTVAL_TWOPOUNDANY)) {
|
|
// Do nothing - defaulted already
|
|
}
|
|
else if (XMLString::equals(nameSpace, SchemaSymbols::fgATTVAL_TWOPOUNDOTHER)) {
|
|
|
|
attType = XMLAttDef::Any_Other;
|
|
uriIndex = fTargetNSURI;
|
|
}
|
|
else {
|
|
|
|
XMLStringTokenizer tokenizer(nameSpace, fGrammarPoolMemoryManager);
|
|
DatatypeValidator* anyURIDV = fDatatypeRegistry->getDatatypeValidator(SchemaSymbols::fgDT_ANYURI);
|
|
|
|
attType = XMLAttDef::Any_List;
|
|
|
|
while (tokenizer.hasMoreTokens()) {
|
|
|
|
const XMLCh* token = tokenizer.nextToken();
|
|
|
|
if (XMLString::equals(token, SchemaSymbols::fgATTVAL_TWOPOUNDLOCAL)) {
|
|
uriIndex = fEmptyNamespaceURI;
|
|
}
|
|
else if (XMLString::equals(token, SchemaSymbols::fgATTVAL_TWOPOUNDTRAGETNAMESPACE)) {
|
|
uriIndex = fTargetNSURI;
|
|
}
|
|
else {
|
|
|
|
try {
|
|
anyURIDV->validate(token
|
|
, fSchemaInfo->getValidationContext()
|
|
, fMemoryManager);
|
|
}
|
|
catch(const XMLException& excep) {
|
|
reportSchemaError(elem, excep);
|
|
}
|
|
uriIndex = fURIStringPool->addOrFind(token);
|
|
}
|
|
|
|
if (!namespaceList.containsElement(uriIndex)) {
|
|
namespaceList.addElement(uriIndex);
|
|
}
|
|
}
|
|
|
|
uriIndex = fEmptyNamespaceURI;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Create wildcard attribute
|
|
// ------------------------------------------------------------------
|
|
SchemaAttDef* attDef = new (fGrammarPoolMemoryManager) SchemaAttDef(XMLUni::fgZeroLenString,
|
|
XMLUni::fgZeroLenString,
|
|
uriIndex, attType, attDefType,
|
|
fGrammarPoolMemoryManager);
|
|
|
|
if (!janAnnot.isDataNull())
|
|
fSchemaGrammar->putAnnotation(attDef, janAnnot.release());
|
|
|
|
if (namespaceList.size()) {
|
|
attDef->setNamespaceList(&namespaceList);
|
|
}
|
|
|
|
return attDef;
|
|
}
|
|
|
|
/**
|
|
* <key
|
|
* id = ID
|
|
* name = NCName
|
|
* Content: (annotation?, (selector, field+))
|
|
* </key>
|
|
*/
|
|
void TraverseSchema::traverseKey(const DOMElement* const icElem,
|
|
SchemaElementDecl* const elemDecl) {
|
|
|
|
NamespaceScopeManager nsMgr(icElem, fSchemaInfo, this);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check Attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
icElem, GeneralAttributeCheck::E_Key, this, false, fNonXSAttList
|
|
);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Create identity constraint
|
|
// -----------------------------------------------------------------------
|
|
const XMLCh* name = getElementAttValue(icElem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
|
|
if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) {
|
|
reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName,
|
|
SchemaSymbols::fgELT_KEY, name);
|
|
return;
|
|
}
|
|
|
|
|
|
if (!fIdentityConstraintNames) {
|
|
fIdentityConstraintNames = new (fMemoryManager) RefHash2KeysTableOf<IdentityConstraint>(29, (bool) false, fMemoryManager);
|
|
}
|
|
else if (fIdentityConstraintNames->containsKey(name, fTargetNSURI)) {
|
|
reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_DuplicateDecl, name);
|
|
return;
|
|
}
|
|
|
|
IC_Key* icKey = new (fGrammarPoolMemoryManager) IC_Key(name, elemDecl->getBaseName(), fGrammarPoolMemoryManager);
|
|
Janitor<IC_Key> janKey(icKey);
|
|
|
|
fIdentityConstraintNames->put((void*) name, fTargetNSURI, icKey);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Get selector and fields
|
|
// -----------------------------------------------------------------------
|
|
if (!traverseIdentityConstraint(icKey, icElem)) {
|
|
|
|
fIdentityConstraintNames->put((void*) name, fTargetNSURI, 0);
|
|
return;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Add key to element declaration
|
|
// -----------------------------------------------------------------------
|
|
elemDecl->addIdentityConstraint(icKey);
|
|
icKey->setNamespaceURI(fTargetNSURI);
|
|
janKey.orphan();
|
|
}
|
|
|
|
/**
|
|
* <unique
|
|
* id = ID
|
|
* name = NCName
|
|
* Content: (annotation?, (selector, field+))
|
|
* </unique>
|
|
*/
|
|
void TraverseSchema::traverseUnique(const DOMElement* const icElem,
|
|
SchemaElementDecl* const elemDecl) {
|
|
|
|
NamespaceScopeManager nsMgr(icElem, fSchemaInfo, this);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check Attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
icElem, GeneralAttributeCheck::E_Unique, this, false, fNonXSAttList
|
|
);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Create identity constraint
|
|
// -----------------------------------------------------------------------
|
|
const XMLCh* name = getElementAttValue(icElem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
|
|
if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) {
|
|
reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName,
|
|
SchemaSymbols::fgELT_UNIQUE, name);
|
|
return;
|
|
}
|
|
|
|
if (!fIdentityConstraintNames) {
|
|
fIdentityConstraintNames = new (fGrammarPoolMemoryManager) RefHash2KeysTableOf<IdentityConstraint>(29, (bool) false, fGrammarPoolMemoryManager);
|
|
}
|
|
else if (fIdentityConstraintNames->containsKey(name, fTargetNSURI)) {
|
|
|
|
reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_DuplicateDecl, name);
|
|
return;
|
|
}
|
|
|
|
IC_Unique* icUnique = new (fGrammarPoolMemoryManager) IC_Unique(name, elemDecl->getBaseName(), fGrammarPoolMemoryManager);
|
|
Janitor<IC_Unique> janUnique(icUnique);
|
|
|
|
fIdentityConstraintNames->put((void*) name, fTargetNSURI, icUnique);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Get selector and fields
|
|
// -----------------------------------------------------------------------
|
|
if (!traverseIdentityConstraint(icUnique, icElem)) {
|
|
|
|
fIdentityConstraintNames->put((void*) name, fTargetNSURI, 0);
|
|
return;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Add identity cosntraints to element declaration
|
|
// -----------------------------------------------------------------------
|
|
elemDecl->addIdentityConstraint(icUnique);
|
|
icUnique->setNamespaceURI(fTargetNSURI);
|
|
janUnique.orphan();
|
|
}
|
|
|
|
/**
|
|
* <keyref
|
|
* id = ID
|
|
* name = NCName
|
|
* refer = QName
|
|
* Content: (annotation?, (selector, field+))
|
|
* </keyref>
|
|
*/
|
|
void TraverseSchema::traverseKeyRef(const DOMElement* const icElem,
|
|
SchemaElementDecl* const elemDecl) {
|
|
|
|
NamespaceScopeManager nsMgr(icElem, fSchemaInfo, this);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Check Attributes
|
|
// -----------------------------------------------------------------------
|
|
fAttributeCheck.checkAttributes(
|
|
icElem, GeneralAttributeCheck::E_KeyRef, this, false, fNonXSAttList
|
|
);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Verify that key reference "refer" attribute is valid
|
|
// -----------------------------------------------------------------------
|
|
const XMLCh* name = getElementAttValue(icElem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
const XMLCh* refer = getElementAttValue(icElem, SchemaSymbols::fgATT_REFER, DatatypeValidator::QName);
|
|
|
|
if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) {
|
|
reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName,
|
|
SchemaSymbols::fgELT_KEYREF, name);
|
|
return;
|
|
}
|
|
|
|
const XMLCh* prefix = getPrefix(refer);
|
|
const XMLCh* localPart = getLocalPart(refer);
|
|
|
|
// we use the DOM API, as the NamespaceScope is now pointing to a different place
|
|
const XMLCh* uriStr = icElem->lookupNamespaceURI(*prefix==0?NULL:prefix);
|
|
if ((!uriStr || !*uriStr) && (prefix && *prefix))
|
|
reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::UnresolvedPrefix, prefix);
|
|
if(!uriStr)
|
|
uriStr=XMLUni::fgZeroLenString;
|
|
|
|
IdentityConstraint* icKey = (fIdentityConstraintNames)
|
|
? fIdentityConstraintNames->get(localPart, fURIStringPool->addOrFind(uriStr)) : 0;
|
|
|
|
if (!icKey) {
|
|
reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_KeyRefReferNotFound, name, localPart);
|
|
return;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Create identity constraint
|
|
// -----------------------------------------------------------------------
|
|
if(fIdentityConstraintNames->containsKey(name, fTargetNSURI)) {
|
|
|
|
reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_DuplicateDecl, name);
|
|
return;
|
|
}
|
|
|
|
IC_KeyRef* icKeyRef = new (fGrammarPoolMemoryManager) IC_KeyRef(name, elemDecl->getBaseName(), icKey, fGrammarPoolMemoryManager);
|
|
Janitor<IC_KeyRef> janKeyRef(icKeyRef);
|
|
|
|
fIdentityConstraintNames->put((void*) name, fTargetNSURI, icKeyRef);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Get selector and fields
|
|
// -----------------------------------------------------------------------
|
|
if (!traverseIdentityConstraint(icKeyRef, icElem)) {
|
|
|
|
fIdentityConstraintNames->put((void*) name, fTargetNSURI, 0);
|
|
return;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Add key reference to element decl
|
|
// -----------------------------------------------------------------------
|
|
if (icKeyRef->getFieldCount() != icKey->getFieldCount()) {
|
|
|
|
fIdentityConstraintNames->put((void*) name, fTargetNSURI, 0);
|
|
reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_KeyRefCardinality,
|
|
name, icKey->getIdentityConstraintName());
|
|
}
|
|
else {
|
|
|
|
elemDecl->addIdentityConstraint(icKeyRef);
|
|
icKeyRef->setNamespaceURI(fTargetNSURI);
|
|
janKeyRef.orphan();
|
|
}
|
|
}
|
|
|
|
|
|
bool TraverseSchema::traverseIdentityConstraint(IdentityConstraint* const ic,
|
|
const DOMElement* const icElem) {
|
|
|
|
NamespaceScopeManager nsMgr(icElem, fSchemaInfo, this);
|
|
|
|
// ------------------------------------------------------------------
|
|
// First, handle any ANNOTATION declaration
|
|
// ------------------------------------------------------------------
|
|
DOMElement* elem = checkContent(icElem, XUtil::getFirstChildElement(icElem), false);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(icElem, fNonXSAttList);
|
|
}
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Get selector
|
|
// ------------------------------------------------------------------
|
|
if (elem == 0) {
|
|
|
|
// reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_BadContent);
|
|
return false;
|
|
}
|
|
|
|
if (!XMLString::equals(elem->getLocalName(), SchemaSymbols::fgELT_SELECTOR)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::IC_BadContent);
|
|
return false;
|
|
}
|
|
|
|
fAttributeCheck.checkAttributes(
|
|
elem, GeneralAttributeCheck::E_Selector, this, false, fNonXSAttList
|
|
);
|
|
if (checkContent(icElem, XUtil::getFirstChildElement(elem), true) != 0)
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
}
|
|
if (fAnnotation)
|
|
{
|
|
if (janAnnot.isDataNull())
|
|
janAnnot.reset(fAnnotation);
|
|
else
|
|
janAnnot.get()->setNext(fAnnotation);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Get xpath attribute
|
|
// ------------------------------------------------------------------
|
|
const XMLCh* xpathExpr = getElementAttValue(elem, SchemaSymbols::fgATT_XPATH);
|
|
XMLSize_t xpathLen = XMLString::stringLen(xpathExpr);
|
|
|
|
if (!xpathExpr || !xpathLen) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::IC_XPathExprMissing);
|
|
return false;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Parse xpath expression
|
|
// ------------------------------------------------------------------
|
|
try {
|
|
|
|
XercesXPath* sXPath = new (fGrammarPoolMemoryManager) XercesXPath(xpathExpr, fStringPool, fSchemaInfo->getNamespaceScope(), fEmptyNamespaceURI, true, fGrammarPoolMemoryManager);
|
|
IC_Selector* icSelector = new (fGrammarPoolMemoryManager) IC_Selector(sXPath, ic);
|
|
ic->setSelector(icSelector);
|
|
}
|
|
catch (const XPathException& e) {
|
|
|
|
reportSchemaError(elem, e);
|
|
return false;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Get fields
|
|
// ------------------------------------------------------------------
|
|
elem = XUtil::getNextSiblingElement(elem);
|
|
|
|
if (elem == 0) {
|
|
|
|
reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_BadContent);
|
|
return false;
|
|
}
|
|
|
|
while (elem != 0) {
|
|
|
|
if (!XMLString::equals(elem->getLocalName(), SchemaSymbols::fgELT_FIELD)) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::IC_BadContent);
|
|
}
|
|
else {
|
|
// General Attribute Checking
|
|
fAttributeCheck.checkAttributes(
|
|
elem, GeneralAttributeCheck::E_Field, this, false, fNonXSAttList
|
|
);
|
|
if (checkContent(icElem, XUtil::getFirstChildElement(elem), true) != 0)
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected);
|
|
if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
|
|
{
|
|
fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
|
|
}
|
|
if (fAnnotation)
|
|
{
|
|
if (janAnnot.isDataNull())
|
|
janAnnot.reset(fAnnotation);
|
|
else
|
|
janAnnot.get()->setNext(fAnnotation);
|
|
}
|
|
|
|
// xpath expression parsing
|
|
xpathExpr = getElementAttValue(elem, SchemaSymbols::fgATT_XPATH);
|
|
|
|
if (!xpathExpr || !*xpathExpr) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::IC_XPathExprMissing);
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
|
|
XercesXPath* fieldXPath = new (fGrammarPoolMemoryManager) XercesXPath
|
|
(
|
|
xpathExpr
|
|
, fStringPool
|
|
, fSchemaInfo->getNamespaceScope()
|
|
, fEmptyNamespaceURI
|
|
, false
|
|
, fGrammarPoolMemoryManager
|
|
);
|
|
IC_Field* icField = new (fGrammarPoolMemoryManager) IC_Field(fieldXPath, ic);
|
|
ic->addField(icField);
|
|
}
|
|
catch (const XPathException& e) {
|
|
|
|
reportSchemaError(elem, e);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
elem = XUtil::getNextSiblingElement(elem);
|
|
}
|
|
|
|
if (!janAnnot.isDataNull())
|
|
fSchemaGrammar->putAnnotation(ic, janAnnot.release());
|
|
|
|
if (ic->getFieldCount() == 0) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// TraverseSchema: Helper methods
|
|
// ---------------------------------------------------------------------------
|
|
bool TraverseSchema::retrieveNamespaceMapping(const DOMElement* const elem) {
|
|
|
|
DOMNamedNodeMap* eltAttrs = elem->getAttributes();
|
|
bool seenNS=false;
|
|
const XMLSize_t attrCount = eltAttrs->getLength();
|
|
|
|
for (XMLSize_t i = 0; i < attrCount; i++) {
|
|
|
|
DOMNode* attribute = eltAttrs->item(i);
|
|
|
|
if (!attribute) {
|
|
break;
|
|
}
|
|
|
|
const XMLCh* attName = attribute->getNodeName();
|
|
|
|
// starts with 'xmlns:'
|
|
if (XMLString::startsWith(attName, XMLUni::fgXMLNSColonString)) {
|
|
if(!seenNS)
|
|
fSchemaInfo->getNamespaceScope()->increaseDepth();
|
|
seenNS=true;
|
|
|
|
int offsetIndex = XMLString::indexOf(attName, chColon);
|
|
const XMLCh* attValue = attribute->getNodeValue();
|
|
|
|
fSchemaInfo->getNamespaceScope()->addPrefix(attName + offsetIndex + 1, fURIStringPool->addOrFind(attValue));
|
|
}
|
|
else if (XMLString::equals(attName, XMLUni::fgXMLNSString)) { // == 'xmlns'
|
|
if(!seenNS)
|
|
fSchemaInfo->getNamespaceScope()->increaseDepth();
|
|
seenNS=true;
|
|
|
|
const XMLCh* attValue = attribute->getNodeValue();
|
|
fSchemaInfo->getNamespaceScope()->addPrefix(XMLUni::fgZeroLenString, fURIStringPool->addOrFind(attValue));
|
|
}
|
|
} // end for
|
|
return seenNS;
|
|
}
|
|
|
|
void TraverseSchema::processChildren(const DOMElement* const root) {
|
|
|
|
NamespaceScopeManager nsMgr(root, fSchemaInfo, this);
|
|
|
|
bool sawAnnotation = false;
|
|
// process <redefine>, <include> and <import> info items.
|
|
DOMElement* child = XUtil::getFirstChildElement(root);
|
|
|
|
for (; child != 0; child = XUtil::getNextSiblingElement(child)) {
|
|
|
|
const XMLCh* name = child->getLocalName();
|
|
|
|
if (XMLString::equals(name, SchemaSymbols::fgELT_ANNOTATION)) {
|
|
XSAnnotation* annot = traverseAnnotationDecl(
|
|
child, fSchemaInfo->getNonXSAttList(), true);
|
|
if (annot) {
|
|
fSchemaGrammar->addAnnotation(annot);
|
|
sawAnnotation = true;
|
|
}
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_INCLUDE)) {
|
|
traverseInclude(child);
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_IMPORT)) {
|
|
traverseImport(child);
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_REDEFINE)) {
|
|
traverseRedefine(child);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
// child refers to the first info item which is not <annotation> or
|
|
// one of the schema inclusion/importation declarations.
|
|
for (; child != 0; child = XUtil::getNextSiblingElement(child)) {
|
|
|
|
const XMLCh* name = child->getLocalName();
|
|
const XMLCh* typeName = getElementAttValue(child, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
int fullNameId = 0;
|
|
|
|
if (typeName) {
|
|
|
|
fBuffer.set(fTargetNSURIString);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(typeName);
|
|
fullNameId = fStringPool->addOrFind(fBuffer.getRawBuffer());
|
|
}
|
|
|
|
if (XMLString::equals(name, SchemaSymbols::fgELT_ANNOTATION)) {
|
|
XSAnnotation* annot = traverseAnnotationDecl(
|
|
child, fSchemaInfo->getNonXSAttList(), true);
|
|
if (annot) {
|
|
fSchemaGrammar->addAnnotation(annot);
|
|
sawAnnotation = true;
|
|
}
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_SIMPLETYPE)) {
|
|
|
|
if (typeName && *typeName) {
|
|
if (fGlobalDeclarations[ENUM_ELT_SIMPLETYPE]->containsElement(fullNameId)
|
|
|| fGlobalDeclarations[ENUM_ELT_COMPLEXTYPE]->containsElement(fullNameId)) {
|
|
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateGlobalType,
|
|
SchemaSymbols::fgELT_SIMPLETYPE, typeName, SchemaSymbols::fgELT_COMPLEXTYPE);
|
|
continue;
|
|
}
|
|
else {
|
|
fGlobalDeclarations[ENUM_ELT_SIMPLETYPE]->addElement(fullNameId);
|
|
}
|
|
}
|
|
|
|
traverseSimpleTypeDecl(child);
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_COMPLEXTYPE)) {
|
|
|
|
if (typeName && *typeName) {
|
|
if (fGlobalDeclarations[ENUM_ELT_SIMPLETYPE]->containsElement(fullNameId)
|
|
|| fGlobalDeclarations[ENUM_ELT_COMPLEXTYPE]->containsElement(fullNameId)) {
|
|
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateGlobalType,
|
|
SchemaSymbols::fgELT_COMPLEXTYPE, typeName, SchemaSymbols::fgELT_SIMPLETYPE);
|
|
continue;
|
|
}
|
|
else {
|
|
fGlobalDeclarations[ENUM_ELT_COMPLEXTYPE]->addElement(fullNameId);
|
|
}
|
|
}
|
|
|
|
traverseComplexTypeDecl(child);
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_ELEMENT)) {
|
|
|
|
if (typeName && *typeName) {
|
|
if (fGlobalDeclarations[ENUM_ELT_ELEMENT]->containsElement(fullNameId)) {
|
|
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateGlobalDeclaration,
|
|
SchemaSymbols::fgELT_ELEMENT, typeName);
|
|
continue;
|
|
}
|
|
else {
|
|
fGlobalDeclarations[ENUM_ELT_ELEMENT]->addElement(fullNameId);
|
|
}
|
|
}
|
|
|
|
traverseElementDecl(child, true);
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_ATTRIBUTEGROUP)) {
|
|
|
|
if (typeName && *typeName) {
|
|
if (fGlobalDeclarations[ENUM_ELT_ATTRIBUTEGROUP]->containsElement(fullNameId)) {
|
|
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateGlobalDeclaration,
|
|
SchemaSymbols::fgELT_ATTRIBUTEGROUP, typeName);
|
|
continue;
|
|
}
|
|
else {
|
|
fGlobalDeclarations[ENUM_ELT_ATTRIBUTEGROUP]->addElement(fullNameId);
|
|
}
|
|
}
|
|
|
|
if (!typeName || !fAttGroupRegistry->containsKey(typeName)) {
|
|
traverseAttributeGroupDecl(child, 0, true);
|
|
}
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_ATTRIBUTE)) {
|
|
|
|
if (typeName && *typeName) {
|
|
if (fGlobalDeclarations[ENUM_ELT_ATTRIBUTE]->containsElement(fullNameId)) {
|
|
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttribute, typeName);
|
|
continue;
|
|
}
|
|
else {
|
|
fGlobalDeclarations[ENUM_ELT_ATTRIBUTE]->addElement(fullNameId);
|
|
}
|
|
}
|
|
|
|
if (!typeName || !fAttributeDeclRegistry->containsKey(typeName)) {
|
|
traverseAttributeDecl( child, 0, true);
|
|
}
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_GROUP)) {
|
|
|
|
if (typeName && *typeName) {
|
|
if (fGlobalDeclarations[ENUM_ELT_GROUP]->containsElement(fullNameId)) {
|
|
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateGlobalDeclaration,
|
|
SchemaSymbols::fgELT_GROUP, typeName);
|
|
continue;
|
|
}
|
|
else {
|
|
fGlobalDeclarations[ENUM_ELT_GROUP]->addElement(fullNameId);
|
|
}
|
|
}
|
|
|
|
if (!typeName || !fGroupRegistry->containsKey(fBuffer.getRawBuffer())) {
|
|
traverseGroupDecl(child);
|
|
}
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_NOTATION)) {
|
|
traverseNotationDecl(child);
|
|
}
|
|
else {
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::SchemaElementContentError);
|
|
}
|
|
} // for each child node
|
|
|
|
|
|
if (fScanner->getGenerateSyntheticAnnotations() && fSchemaInfo->getNonXSAttList()->size() && !sawAnnotation)
|
|
{
|
|
// synthesize a global annotation here.
|
|
fSchemaGrammar->addAnnotation(
|
|
generateSyntheticAnnotation(root, fSchemaInfo->getNonXSAttList())
|
|
);
|
|
}
|
|
|
|
// Handle recursing elements - if any
|
|
ValueVectorOf<const DOMElement*>* recursingAnonTypes = fSchemaInfo->getRecursingAnonTypes();
|
|
|
|
if (recursingAnonTypes) {
|
|
|
|
ValueVectorOf<const XMLCh*>* recursingTypeNames = fSchemaInfo->getRecursingTypeNames();
|
|
XMLSize_t recurseSize = recursingAnonTypes->size();
|
|
|
|
for (XMLSize_t i=0; i < recurseSize; i++) {
|
|
traverseComplexTypeDecl(recursingAnonTypes->elementAt(i), false,
|
|
recursingTypeNames->elementAt(i));
|
|
}
|
|
|
|
recursingAnonTypes->removeAllElements();
|
|
recursingTypeNames->removeAllElements();
|
|
}
|
|
}
|
|
|
|
void TraverseSchema::preprocessChildren(const DOMElement* const root) {
|
|
|
|
NamespaceScopeManager nsMgr(root, fSchemaInfo, this);
|
|
|
|
// process <redefine>, <include> and <import> info items.
|
|
DOMElement* child = XUtil::getFirstChildElement(root);
|
|
|
|
for (; child != 0; child = XUtil::getNextSiblingElement(child)) {
|
|
|
|
const XMLCh* name = child->getLocalName();
|
|
|
|
if (XMLString::equals(name, SchemaSymbols::fgELT_ANNOTATION)) {
|
|
continue;
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_INCLUDE)) {
|
|
preprocessInclude(child);
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_IMPORT)) {
|
|
preprocessImport(child);
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_REDEFINE)) {
|
|
preprocessRedefine(child);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
DOMElement* TraverseSchema::checkContent( const DOMElement* const rootElem
|
|
, DOMElement* const contentElem
|
|
, const bool isEmpty
|
|
, const bool processAnnot)
|
|
{
|
|
DOMElement* content = contentElem;
|
|
const XMLCh* name = getElementAttValue(rootElem,SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
|
|
fAnnotation = 0;
|
|
Janitor<XSAnnotation> janAnnot(0);
|
|
if (!content) {
|
|
|
|
if (!isEmpty) {
|
|
reportSchemaError(rootElem, XMLUni::fgXMLErrDomain, XMLErrs::ContentError, name);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_ANNOTATION)) {
|
|
|
|
if (processAnnot) {
|
|
janAnnot.reset(traverseAnnotationDecl(content, fNonXSAttList));
|
|
}
|
|
content = XUtil::getNextSiblingElement(content);
|
|
|
|
if (!content) { // must be followed by content
|
|
|
|
if (!isEmpty) {
|
|
reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::ContentError, name);
|
|
}
|
|
fAnnotation = janAnnot.release();
|
|
return 0;
|
|
}
|
|
|
|
if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_ANNOTATION)) {
|
|
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::AnnotationError, name);
|
|
return 0;
|
|
}
|
|
fAnnotation = janAnnot.release();
|
|
}
|
|
return content;
|
|
}
|
|
|
|
|
|
DatatypeValidator*
|
|
TraverseSchema::getDatatypeValidator(const XMLCh* const uriStr,
|
|
const XMLCh* const localPartStr) {
|
|
|
|
DatatypeValidator* dv = 0;
|
|
|
|
if (XMLString::equals(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {
|
|
dv = fDatatypeRegistry->getDatatypeValidator(localPartStr);
|
|
}
|
|
else {
|
|
|
|
fBuffer.set(uriStr);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(localPartStr);
|
|
|
|
if ((uriStr) && !XMLString::equals(uriStr, fTargetNSURIString)) {
|
|
|
|
Grammar* grammar = fGrammarResolver->getGrammar(uriStr);
|
|
|
|
if (grammar && grammar->getGrammarType() == Grammar::SchemaGrammarType) {
|
|
dv = ((SchemaGrammar*) grammar)->getDatatypeRegistry()->getDatatypeValidator(fBuffer.getRawBuffer());
|
|
}
|
|
}
|
|
else {
|
|
dv = fDatatypeRegistry->getDatatypeValidator(fBuffer.getRawBuffer());
|
|
}
|
|
}
|
|
|
|
return dv;
|
|
}
|
|
|
|
|
|
DatatypeValidator*
|
|
TraverseSchema::checkForSimpleTypeValidator(const DOMElement* const content,
|
|
int baseRefContext) {
|
|
|
|
DatatypeValidator* baseValidator = traverseSimpleTypeDecl(content, false, baseRefContext);
|
|
|
|
if (!baseValidator) {
|
|
|
|
const XMLCh* name = getElementAttValue(content,SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::UnknownSimpleType, name);
|
|
}
|
|
|
|
return baseValidator;
|
|
}
|
|
|
|
ComplexTypeInfo*
|
|
TraverseSchema::checkForComplexTypeInfo(const DOMElement* const content) {
|
|
|
|
int typeNameIndex = traverseComplexTypeDecl(content, false);
|
|
ComplexTypeInfo* baseTypeInfo = 0;
|
|
|
|
if (typeNameIndex != -1) {
|
|
baseTypeInfo = fComplexTypeRegistry->get(fStringPool->getValueForId(typeNameIndex));
|
|
}
|
|
|
|
if (typeNameIndex == -1 || baseTypeInfo == 0) {
|
|
|
|
const XMLCh* name = getElementAttValue(content,SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::UnknownComplexType, name);
|
|
}
|
|
|
|
return baseTypeInfo;
|
|
}
|
|
|
|
DatatypeValidator*
|
|
TraverseSchema::findDTValidator(const DOMElement* const elem,
|
|
const XMLCh* const derivedTypeName,
|
|
const XMLCh* const baseTypeName,
|
|
const int baseRefContext) {
|
|
|
|
const XMLCh* prefix = getPrefix(baseTypeName);
|
|
const XMLCh* localPart = getLocalPart(baseTypeName);
|
|
const XMLCh* uri = resolvePrefixToURI(elem, prefix);
|
|
DatatypeValidator* baseValidator = getDatatypeValidator(uri, localPart);
|
|
|
|
if (baseValidator == 0) {
|
|
|
|
// Check if the base is from the schema for schema namespace
|
|
//
|
|
if (XMLString::equals(uri, SchemaSymbols::fgURI_SCHEMAFORSCHEMA))
|
|
{
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, uri, localPart);
|
|
return 0;
|
|
}
|
|
|
|
SchemaInfo::ListType infoType = SchemaInfo::INCLUDE;
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
unsigned int saveScope = fCurrentScope;
|
|
|
|
if (!XMLString::equals(uri, fTargetNSURIString) && (uri && *uri)) {
|
|
|
|
// Make sure that we have an explicit import statement.
|
|
// Clause 4 of Schema Representation Constraint:
|
|
// http://www.w3.org/TR/xmlschema-1/#src-resolve
|
|
unsigned int uriId = fURIStringPool->addOrFind(uri);
|
|
|
|
if (!isImportingNS(uriId)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, uri);
|
|
return 0;
|
|
}
|
|
|
|
SchemaInfo* impInfo = fSchemaInfo->getImportInfo(uriId);
|
|
|
|
if (!impInfo || impInfo->getProcessed())
|
|
{
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, uri, localPart);
|
|
return 0;
|
|
}
|
|
|
|
infoType = SchemaInfo::IMPORT;
|
|
restoreSchemaInfo(impInfo, infoType);
|
|
}
|
|
|
|
DOMElement* baseTypeNode = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_SimpleType,
|
|
SchemaSymbols::fgELT_SIMPLETYPE, localPart, &fSchemaInfo);
|
|
|
|
if (baseTypeNode != 0) {
|
|
|
|
baseValidator = traverseSimpleTypeDecl(baseTypeNode);
|
|
|
|
// restore schema information, if necessary
|
|
if (saveInfo != fSchemaInfo) {
|
|
restoreSchemaInfo(saveInfo, infoType, saveScope);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (baseValidator == 0) {
|
|
reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::UnknownBaseDatatype, baseTypeName, derivedTypeName);
|
|
}
|
|
else if ((baseValidator->getFinalSet() & baseRefContext) != 0) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DisallowedBaseDerivation, baseTypeName);
|
|
return 0;
|
|
}
|
|
|
|
return baseValidator;
|
|
}
|
|
|
|
|
|
const XMLCh* TraverseSchema::resolvePrefixToURI(const DOMElement* const elem,
|
|
const XMLCh* const prefix) {
|
|
|
|
unsigned int nameSpaceIndex = fSchemaInfo->getNamespaceScope()->getNamespaceForPrefix(prefix);
|
|
const XMLCh* uriStr = fURIStringPool->getValueForId(nameSpaceIndex);
|
|
|
|
if ((!uriStr || !*uriStr) && (prefix && *prefix)) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::UnresolvedPrefix, prefix);
|
|
return XMLUni::fgZeroLenString;
|
|
}
|
|
|
|
return uriStr;
|
|
}
|
|
|
|
SchemaElementDecl*
|
|
TraverseSchema::processElementDeclRef(const DOMElement* const elem,
|
|
const XMLCh* const refName)
|
|
{
|
|
// check attributes
|
|
fAttributeCheck.checkAttributes(
|
|
elem, GeneralAttributeCheck::E_ElementRef, this, false, fNonXSAttList
|
|
);
|
|
|
|
// handle annotation
|
|
DOMElement* content = checkContent(elem, XUtil::getFirstChildElement(elem), true);
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
|
|
// do not generate synthetic annotation for element reference...
|
|
|
|
if (content != 0)
|
|
reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::NoContentForRef, SchemaSymbols::fgELT_ELEMENT);
|
|
|
|
SchemaElementDecl* refElemDecl = getGlobalElemDecl(elem, refName);
|
|
|
|
if (!refElemDecl)
|
|
{
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::RefElementNotFound, refName);
|
|
}
|
|
else
|
|
{
|
|
if (fCurrentComplexType)
|
|
fCurrentComplexType->addElement(refElemDecl);
|
|
|
|
if (fCurrentGroupInfo)
|
|
fCurrentGroupInfo->addElement(refElemDecl);
|
|
}
|
|
|
|
return refElemDecl;
|
|
}
|
|
|
|
int TraverseSchema::parseBlockSet(const DOMElement* const elem,
|
|
const int blockType, const bool isRoot) {
|
|
|
|
const XMLCh* blockVal = (isRoot) ? getElementAttValue(elem, SchemaSymbols::fgATT_BLOCKDEFAULT)
|
|
: getElementAttValue(elem, SchemaSymbols::fgATT_BLOCK);
|
|
|
|
// blockVal == 0 means 'block attribute is missing'; *blockVal == 0 means 'block="" found'
|
|
if (blockVal == 0)
|
|
return fSchemaInfo->getBlockDefault();
|
|
|
|
int blockSet = 0;
|
|
|
|
if (XMLString::equals(blockVal, SchemaSymbols::fgATTVAL_POUNDALL)) {
|
|
|
|
blockSet = SchemaSymbols::XSD_EXTENSION + SchemaSymbols::XSD_RESTRICTION + SchemaSymbols::XSD_SUBSTITUTION;
|
|
return blockSet;
|
|
}
|
|
|
|
XMLStringTokenizer tokenizer(blockVal, fGrammarPoolMemoryManager);
|
|
|
|
while (tokenizer.hasMoreTokens()) {
|
|
|
|
XMLCh* token = tokenizer.nextToken();
|
|
|
|
if (XMLString::equals(token, SchemaSymbols::fgATTVAL_SUBSTITUTION)
|
|
&& blockType == ES_Block) {
|
|
|
|
if ((blockSet & SchemaSymbols::XSD_SUBSTITUTION) == 0 ) {
|
|
blockSet += SchemaSymbols::XSD_SUBSTITUTION;
|
|
}
|
|
}
|
|
else if (XMLString::equals(token, SchemaSymbols::fgATTVAL_EXTENSION)) {
|
|
|
|
if ((blockSet & SchemaSymbols::XSD_EXTENSION) == 0) {
|
|
blockSet += SchemaSymbols::XSD_EXTENSION;
|
|
}
|
|
}
|
|
else if (XMLString::equals(token, SchemaSymbols::fgATTVAL_RESTRICTION)) {
|
|
|
|
if ((blockSet & SchemaSymbols::XSD_RESTRICTION) == 0 ) {
|
|
blockSet += SchemaSymbols::XSD_RESTRICTION;
|
|
}
|
|
}
|
|
else {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidBlockValue, blockVal);
|
|
}
|
|
} //end while
|
|
|
|
return blockSet;
|
|
}
|
|
|
|
int TraverseSchema::parseFinalSet(const DOMElement* const elem,
|
|
const int finalType, const bool isRoot) {
|
|
|
|
const XMLCh* finalVal = (isRoot) ? getElementAttValue(elem, SchemaSymbols::fgATT_FINALDEFAULT)
|
|
: getElementAttValue(elem, SchemaSymbols::fgATT_FINAL);
|
|
|
|
// finalVal == 0 means 'final attribute is missing'; *finalVal == 0 means 'final="" found'
|
|
if (finalVal == 0)
|
|
return fSchemaInfo->getFinalDefault();
|
|
|
|
int finalSet = 0;
|
|
|
|
if (XMLString::equals(finalVal, SchemaSymbols::fgATTVAL_POUNDALL)) {
|
|
|
|
finalSet = SchemaSymbols::XSD_RESTRICTION + SchemaSymbols::XSD_LIST +
|
|
SchemaSymbols::XSD_UNION + SchemaSymbols::XSD_EXTENSION;
|
|
return finalSet;
|
|
}
|
|
|
|
XMLStringTokenizer tokenizer(finalVal, fGrammarPoolMemoryManager);
|
|
|
|
while (tokenizer.hasMoreTokens()) {
|
|
|
|
XMLCh* token = tokenizer.nextToken();
|
|
|
|
if (XMLString::equals(token, SchemaSymbols::fgELT_UNION)
|
|
&& (finalType == S_Final || finalType == ECS_Final)) {
|
|
|
|
if ((finalSet & SchemaSymbols::XSD_UNION) == 0) {
|
|
finalSet += SchemaSymbols::XSD_UNION;
|
|
}
|
|
}
|
|
else if (XMLString::equals(token, SchemaSymbols::fgATTVAL_EXTENSION)
|
|
&& (finalType == EC_Final || finalType == ECS_Final)) {
|
|
|
|
if ((finalSet & SchemaSymbols::XSD_EXTENSION) == 0) {
|
|
finalSet += SchemaSymbols::XSD_EXTENSION;
|
|
}
|
|
}
|
|
else if (XMLString::equals(token, SchemaSymbols::fgELT_LIST)
|
|
&& (finalType == S_Final || finalType == ECS_Final)) {
|
|
|
|
if ((finalSet & SchemaSymbols::XSD_LIST) == 0 ) {
|
|
finalSet += SchemaSymbols::XSD_LIST;
|
|
}
|
|
}
|
|
else if (XMLString::equals(token, SchemaSymbols::fgATTVAL_RESTRICTION)) {
|
|
|
|
if ((finalSet & SchemaSymbols::XSD_RESTRICTION) == 0 ) {
|
|
finalSet += SchemaSymbols::XSD_RESTRICTION;
|
|
}
|
|
}
|
|
else {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidFinalValue, finalVal);
|
|
}
|
|
} //end while
|
|
|
|
return finalSet;
|
|
}
|
|
|
|
|
|
const DOMElement*
|
|
TraverseSchema::checkIdentityConstraintContent(const DOMElement* const content) {
|
|
|
|
const DOMElement* child = content;
|
|
|
|
if (child != 0) {
|
|
|
|
do {
|
|
|
|
if (!isIdentityConstraintName(child->getLocalName())) {
|
|
break;
|
|
}
|
|
|
|
child = XUtil::getNextSiblingElement(child);
|
|
|
|
} while (child != 0);
|
|
}
|
|
|
|
return child;
|
|
}
|
|
|
|
bool TraverseSchema::isIdentityConstraintName(const XMLCh* const name) {
|
|
|
|
return (XMLString::equals(name, SchemaSymbols::fgELT_KEY)
|
|
|| XMLString::equals(name, SchemaSymbols::fgELT_KEYREF)
|
|
|| XMLString::equals(name, SchemaSymbols::fgELT_UNIQUE));
|
|
}
|
|
|
|
const XMLCh*
|
|
TraverseSchema::checkTypeFromAnotherSchema(const DOMElement* const elem,
|
|
const XMLCh* const typeStr) {
|
|
|
|
const XMLCh* prefix = getPrefix(typeStr);
|
|
const XMLCh* typeURI = resolvePrefixToURI(elem, prefix);
|
|
|
|
if (!XMLString::equals(typeURI, fTargetNSURIString)
|
|
&& !XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)
|
|
) {
|
|
return typeURI;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
DatatypeValidator*
|
|
TraverseSchema::getElementTypeValidator(const DOMElement* const elem,
|
|
const XMLCh* const typeStr,
|
|
bool& noErrorDetected,
|
|
const XMLCh* const otherSchemaURI)
|
|
{
|
|
const XMLCh* localPart = getLocalPart(typeStr);
|
|
const XMLCh* typeURI = otherSchemaURI;
|
|
DatatypeValidator* dv = 0;
|
|
SchemaInfo::ListType infoType = SchemaInfo::INCLUDE;
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
unsigned int saveScope = fCurrentScope;
|
|
|
|
if (otherSchemaURI && *otherSchemaURI) {
|
|
|
|
// Make sure that we have an explicit import statement.
|
|
// Clause 4 of Schema Representation Constraint:
|
|
// http://www.w3.org/TR/xmlschema-1/#src-resolve
|
|
unsigned int uriId = fURIStringPool->addOrFind(otherSchemaURI);
|
|
|
|
if (!isImportingNS(uriId)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, otherSchemaURI);
|
|
return 0;
|
|
}
|
|
|
|
dv = getDatatypeValidator(typeURI, localPart);
|
|
|
|
if (dv) {
|
|
return dv;
|
|
}
|
|
|
|
SchemaInfo* impInfo = fSchemaInfo->getImportInfo(uriId);
|
|
|
|
if (!impInfo || impInfo->getProcessed()) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, typeURI, localPart);
|
|
return 0;
|
|
}
|
|
|
|
infoType = SchemaInfo::IMPORT;
|
|
restoreSchemaInfo(impInfo, infoType);
|
|
}
|
|
else {
|
|
const XMLCh* prefix = getPrefix(typeStr);
|
|
|
|
typeURI = resolvePrefixToURI(elem, prefix);
|
|
dv = getDatatypeValidator(typeURI, localPart);
|
|
}
|
|
|
|
if (!dv) {
|
|
|
|
if (!XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)
|
|
|| XMLString::equals(fTargetNSURIString, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {
|
|
|
|
DOMElement* typeElem = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_SimpleType,
|
|
SchemaSymbols::fgELT_SIMPLETYPE, localPart, &fSchemaInfo);
|
|
|
|
if (typeElem) {
|
|
traverseSimpleTypeDecl(typeElem);
|
|
dv = getDatatypeValidator(typeURI, localPart);
|
|
}
|
|
}
|
|
|
|
// restore schema information, if necessary
|
|
if (saveInfo != fSchemaInfo) {
|
|
restoreSchemaInfo(saveInfo, infoType, saveScope);
|
|
}
|
|
|
|
if (!dv) {
|
|
|
|
noErrorDetected = false;
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, typeURI, localPart);
|
|
}
|
|
}
|
|
|
|
return dv;
|
|
}
|
|
|
|
|
|
DatatypeValidator*
|
|
TraverseSchema::getAttrDatatypeValidatorNS(const DOMElement* const elem,
|
|
const XMLCh* localPart,
|
|
const XMLCh* typeURI)
|
|
{
|
|
DatatypeValidator* dv = getDatatypeValidator(typeURI, localPart);
|
|
SchemaInfo::ListType infoType = SchemaInfo::INCLUDE;
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
unsigned int saveScope = fCurrentScope;
|
|
|
|
if (!XMLString::equals(typeURI, fTargetNSURIString)
|
|
&& (typeURI && *typeURI)) {
|
|
|
|
// Make sure that we have an explicit import statement.
|
|
// Clause 4 of Schema Representation Constraint:
|
|
// http://www.w3.org/TR/xmlschema-1/#src-resolve
|
|
unsigned int uriId = fURIStringPool->addOrFind(typeURI);
|
|
|
|
if (!isImportingNS(uriId)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, typeURI);
|
|
return 0;
|
|
}
|
|
|
|
if (!dv) {
|
|
SchemaInfo* impInfo = fSchemaInfo->getImportInfo(uriId);
|
|
|
|
if (!impInfo || impInfo->getProcessed())
|
|
{
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, typeURI, localPart);
|
|
return 0;
|
|
}
|
|
|
|
infoType = SchemaInfo::IMPORT;
|
|
restoreSchemaInfo(impInfo, infoType);
|
|
}
|
|
}
|
|
|
|
if (!dv) {
|
|
|
|
DOMElement* typeElem = fSchemaInfo->getTopLevelComponent
|
|
(
|
|
SchemaInfo::C_SimpleType
|
|
, SchemaSymbols::fgELT_SIMPLETYPE
|
|
, localPart
|
|
, &fSchemaInfo
|
|
);
|
|
|
|
if (typeElem)
|
|
dv = traverseSimpleTypeDecl(typeElem);
|
|
|
|
// restore schema information, if necessary
|
|
if (saveInfo != fSchemaInfo) {
|
|
restoreSchemaInfo(saveInfo, infoType, saveScope);
|
|
}
|
|
}
|
|
|
|
return dv;
|
|
}
|
|
|
|
ComplexTypeInfo*
|
|
TraverseSchema::getElementComplexTypeInfo(const DOMElement* const elem,
|
|
const XMLCh* const typeStr,
|
|
const XMLCh* const otherSchemaURI)
|
|
{
|
|
const XMLCh* localPart = getLocalPart(typeStr);
|
|
const XMLCh* prefix = getPrefix(typeStr);
|
|
const XMLCh* typeURI = (otherSchemaURI) ? otherSchemaURI : resolvePrefixToURI(elem, prefix);
|
|
ComplexTypeInfo* typeInfo = 0;
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
SchemaInfo::ListType infoType = SchemaInfo::INCLUDE;
|
|
unsigned int saveScope = fCurrentScope;
|
|
|
|
fBuffer.set(typeURI);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(localPart);
|
|
|
|
if (otherSchemaURI != 0) {
|
|
|
|
// Make sure that we have an explicit import statement.
|
|
// Clause 4 of Schema Representation Constraint:
|
|
// http://www.w3.org/TR/xmlschema-1/#src-resolve
|
|
unsigned int uriId = fURIStringPool->addOrFind(typeURI);
|
|
|
|
if (!isImportingNS(uriId))
|
|
return 0;
|
|
|
|
Grammar* aGrammar = fGrammarResolver->getGrammar(typeURI);
|
|
|
|
if (!aGrammar || aGrammar->getGrammarType() != Grammar::SchemaGrammarType) {
|
|
return 0;
|
|
}
|
|
|
|
typeInfo = ((SchemaGrammar*)aGrammar)->getComplexTypeRegistry()->get(fBuffer.getRawBuffer());
|
|
|
|
if (typeInfo) {
|
|
return typeInfo;
|
|
}
|
|
|
|
SchemaInfo* impInfo = fSchemaInfo->getImportInfo(uriId);
|
|
|
|
if (!impInfo || impInfo->getProcessed()) {
|
|
return 0;
|
|
}
|
|
|
|
infoType = SchemaInfo::IMPORT;
|
|
restoreSchemaInfo(impInfo, infoType);
|
|
}
|
|
else {
|
|
typeInfo = fComplexTypeRegistry->get(fBuffer.getRawBuffer());
|
|
}
|
|
|
|
if (!typeInfo) {
|
|
if (!XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA) ||
|
|
XMLString::equals(fTargetNSURIString, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {
|
|
|
|
DOMElement* typeNode = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_ComplexType,
|
|
SchemaSymbols::fgELT_COMPLEXTYPE, localPart, &fSchemaInfo);
|
|
|
|
if (typeNode) {
|
|
// fBuffer is reused by traverseComplexTypeDecl, so we have to store its current value
|
|
XMLBuffer buffCopy(fBuffer.getLen()+1, fMemoryManager);
|
|
buffCopy.set(fBuffer.getRawBuffer());
|
|
traverseComplexTypeDecl(typeNode);
|
|
typeInfo = fComplexTypeRegistry->get(buffCopy.getRawBuffer());
|
|
}
|
|
}
|
|
}
|
|
|
|
// restore schema information
|
|
restoreSchemaInfo(saveInfo, infoType, saveScope);
|
|
return typeInfo;
|
|
}
|
|
|
|
|
|
SchemaElementDecl*
|
|
TraverseSchema::getGlobalElemDecl(const DOMElement* const elem,
|
|
const XMLCh* const qName)
|
|
{
|
|
const XMLCh* nameURI = resolvePrefixToURI(elem, getPrefix(qName));
|
|
const XMLCh* localPart = getLocalPart(qName);
|
|
SchemaElementDecl* elemDecl = 0;
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
SchemaInfo::ListType infoType = SchemaInfo::INCLUDE;
|
|
unsigned int saveScope = fCurrentScope;
|
|
unsigned int uriId = fURIStringPool->addOrFind(nameURI);
|
|
|
|
if (fSchemaInfo->getTargetNSURI() != (int) uriId)
|
|
{
|
|
//if (!XMLString::equals(nameURI, fTargetNSURIString)) {
|
|
|
|
// Make sure that we have an explicit import statement.
|
|
// Clause 4 of Schema Representation Constraint:
|
|
// http://www.w3.org/TR/xmlschema-1/#src-resolve
|
|
if (!isImportingNS(uriId))
|
|
{
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, nameURI);
|
|
return 0;
|
|
}
|
|
|
|
Grammar* grammar = fGrammarResolver->getGrammar(nameURI);
|
|
|
|
if (grammar && grammar->getGrammarType() == Grammar::SchemaGrammarType)
|
|
{
|
|
elemDecl = (SchemaElementDecl*) grammar->getElemDecl(
|
|
uriId, localPart, 0, Grammar::TOP_LEVEL_SCOPE);
|
|
}
|
|
else
|
|
{
|
|
reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::GrammarNotFound, nameURI);
|
|
return 0;
|
|
}
|
|
|
|
if (!elemDecl)
|
|
{
|
|
SchemaInfo* impInfo = fSchemaInfo->getImportInfo(uriId);
|
|
if (!impInfo || impInfo->getProcessed())
|
|
{
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, nameURI, localPart);
|
|
return 0;
|
|
}
|
|
|
|
infoType = SchemaInfo::IMPORT;
|
|
restoreSchemaInfo(impInfo, infoType);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
elemDecl = (SchemaElementDecl*)
|
|
fSchemaGrammar->getElemDecl(fTargetNSURI, localPart, 0, Grammar::TOP_LEVEL_SCOPE);
|
|
}
|
|
|
|
if (!elemDecl)
|
|
{
|
|
DOMElement* subsGroupElem = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_Element,
|
|
SchemaSymbols::fgELT_ELEMENT,localPart, &fSchemaInfo);
|
|
|
|
if (subsGroupElem)
|
|
elemDecl = traverseElementDecl(subsGroupElem, true);
|
|
|
|
if (!elemDecl)
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, nameURI, localPart);
|
|
}
|
|
|
|
// restore schema information, if necessary
|
|
if (saveInfo != fSchemaInfo) {
|
|
restoreSchemaInfo(saveInfo, infoType, saveScope);
|
|
}
|
|
|
|
return elemDecl;
|
|
}
|
|
|
|
bool
|
|
TraverseSchema::isSubstitutionGroupValid(const DOMElement* const elem,
|
|
const SchemaElementDecl* const subsElemDecl,
|
|
const ComplexTypeInfo* const typeInfo,
|
|
const DatatypeValidator* const validator,
|
|
const XMLCh* const elemName,
|
|
const bool toEmit) {
|
|
|
|
// here we must do two things:
|
|
// 1. Make sure there actually *is* a relation between the types of
|
|
// the element being nominated and the element doing the nominating;
|
|
// (see PR 3.3.6 point #3 in the first tableau, for instance; this
|
|
// and the corresponding tableaux from 3.4.6 and 3.14.6 rule out the nominated
|
|
// element having an anonymous type declaration.
|
|
// 2. Make sure the nominated element allows itself to be nominated by
|
|
// an element with the given type-relation.
|
|
// Note: we assume that (complex|simple)Type processing checks
|
|
// whether the type in question allows itself to
|
|
// be modified as this element desires.
|
|
|
|
// if substitution element has any as content model type, return true
|
|
bool subsRestricted = false;
|
|
if (subsElemDecl->getModelType() == SchemaElementDecl::Any) {
|
|
|
|
if ((subsElemDecl->getFinalSet() & SchemaSymbols::XSD_RESTRICTION) == 0
|
|
|| (typeInfo == 0 && validator == 0))
|
|
return true;
|
|
else
|
|
subsRestricted = true;
|
|
}
|
|
// Check for type relationship;
|
|
// that is, make sure that the type we're deriving has some relatoinship
|
|
// to substitutionGroupElt's type.
|
|
else if (typeInfo) { // do complexType case ...need testing
|
|
|
|
ComplexTypeInfo* subsTypeInfo = subsElemDecl->getComplexTypeInfo();
|
|
|
|
if (subsTypeInfo == typeInfo)
|
|
return true;
|
|
|
|
int derivationMethod = typeInfo->getDerivedBy();
|
|
|
|
if (subsTypeInfo == 0) { // take care of complexType based on simpleType case...
|
|
|
|
DatatypeValidator* elemDV = typeInfo->getDatatypeValidator();
|
|
DatatypeValidator* subsValidator = subsElemDecl->getDatatypeValidator();
|
|
|
|
if (elemDV == subsValidator) {
|
|
return true;
|
|
}
|
|
else if (subsValidator && subsValidator->isSubstitutableBy(elemDV)) {
|
|
if ((subsElemDecl->getFinalSet() & derivationMethod) == 0) {
|
|
return true;
|
|
}
|
|
else {
|
|
subsRestricted = true;
|
|
}
|
|
}
|
|
}
|
|
else { // complex content
|
|
|
|
const ComplexTypeInfo* elemTypeInfo = typeInfo;
|
|
|
|
for (; elemTypeInfo && elemTypeInfo != subsTypeInfo;
|
|
elemTypeInfo = elemTypeInfo->getBaseComplexTypeInfo()) {
|
|
}
|
|
|
|
if (elemTypeInfo) {
|
|
if ((subsElemDecl->getFinalSet() & derivationMethod) == 0) {
|
|
return true;
|
|
}
|
|
else {
|
|
subsRestricted = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (validator) { // do simpleType case...
|
|
|
|
if (!subsElemDecl->getComplexTypeInfo()) {
|
|
// first, check for type relation.
|
|
DatatypeValidator* subsValidator = subsElemDecl->getDatatypeValidator();
|
|
|
|
if (subsValidator == validator) {
|
|
return true;
|
|
}
|
|
else if (subsValidator && subsValidator->isSubstitutableBy(validator)
|
|
&& ((subsElemDecl->getFinalSet() & SchemaSymbols::XSD_RESTRICTION) == 0)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
else // validator==0 && typeInfo==0 -- no checking
|
|
return true;
|
|
|
|
if (toEmit) {
|
|
if (subsRestricted) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidSubstitutionGroupElement,
|
|
elemName, subsElemDecl->getBaseName());
|
|
}
|
|
else {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::SubstitutionGroupTypeMismatch, elemName);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
SchemaElementDecl*
|
|
TraverseSchema::createSchemaElementDecl(const DOMElement* const elem,
|
|
const XMLCh* const name,
|
|
bool& isDuplicate,
|
|
const XMLCh*& valConstraint,
|
|
const bool topLevel)
|
|
{
|
|
unsigned int enclosingScope = fCurrentScope;
|
|
int uriIndex = fEmptyNamespaceURI;
|
|
|
|
if (topLevel) {
|
|
|
|
uriIndex = fTargetNSURI;
|
|
enclosingScope = Grammar::TOP_LEVEL_SCOPE;
|
|
}
|
|
else
|
|
{
|
|
const XMLCh* elemForm = getElementAttValue(elem, SchemaSymbols::fgATT_FORM);
|
|
|
|
if (((!elemForm || !*elemForm) &&
|
|
(fSchemaInfo->getElemAttrDefaultQualified() & Elem_Def_Qualified))
|
|
|| XMLString::equals(elemForm,SchemaSymbols::fgATTVAL_QUALIFIED))
|
|
uriIndex = fTargetNSURI;
|
|
|
|
// Check for duplicate elements
|
|
SchemaElementDecl* other = (SchemaElementDecl*)
|
|
fSchemaGrammar->getElemDecl(uriIndex, name, 0, enclosingScope);
|
|
|
|
if (other != 0)
|
|
{
|
|
isDuplicate = true;
|
|
return other;
|
|
}
|
|
}
|
|
|
|
// create element decl and add it to the grammar
|
|
Janitor<SchemaElementDecl> elemDecl(new (fGrammarPoolMemoryManager) SchemaElementDecl(
|
|
XMLUni::fgZeroLenString , name, uriIndex , SchemaElementDecl::Any
|
|
, enclosingScope , fGrammarPoolMemoryManager
|
|
));
|
|
|
|
elemDecl->setCreateReason(XMLElementDecl::Declared);
|
|
|
|
if (topLevel)
|
|
elemDecl->setPSVIScope(PSVIDefs::SCP_GLOBAL);
|
|
|
|
// process attributes
|
|
processElemDeclAttrs(elem, elemDecl.get(), valConstraint, topLevel);
|
|
|
|
return elemDecl.release();
|
|
}
|
|
|
|
|
|
void TraverseSchema::processAttributeDeclRef(const DOMElement* const elem,
|
|
ComplexTypeInfo* const typeInfo,
|
|
const XMLCh* const refName,
|
|
const XMLCh* const useAttr,
|
|
const XMLCh* const defaultVal,
|
|
const XMLCh* const fixedVal) {
|
|
|
|
if (!typeInfo && !fCurrentAttGroupInfo) {
|
|
return;
|
|
}
|
|
|
|
const XMLCh* prefix = getPrefix(refName);
|
|
const XMLCh* localPart = getLocalPart(refName);
|
|
const XMLCh* uriStr = resolvePrefixToURI(elem, prefix);
|
|
unsigned int attURI = fURIStringPool->addOrFind(uriStr);
|
|
|
|
// Check for duplicate references
|
|
if (typeInfo && typeInfo->getAttDef(localPart, attURI)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateRefAttribute, uriStr, localPart);
|
|
return;
|
|
}
|
|
else if (fCurrentAttGroupInfo && fCurrentAttGroupInfo->containsAttribute(localPart, attURI)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateRefAttribute, uriStr, localPart);
|
|
return;
|
|
}
|
|
|
|
// check for different namespace
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
SchemaInfo::ListType infoType = SchemaInfo::INCLUDE;
|
|
SchemaAttDef* refAttDef = 0;
|
|
unsigned int saveScope = fCurrentScope;
|
|
|
|
if (!XMLString::equals(uriStr, fTargetNSURIString)) {
|
|
|
|
// Make sure that we have an explicit import statement.
|
|
// Clause 4 of Schema Representation Constraint:
|
|
// http://www.w3.org/TR/xmlschema-1/#src-resolve
|
|
unsigned int uriId = fURIStringPool->addOrFind(uriStr);
|
|
|
|
if (!isImportingNS(uriId)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, uriStr);
|
|
return;
|
|
}
|
|
|
|
Grammar* grammar = fGrammarResolver->getGrammar(uriStr);
|
|
|
|
if (grammar == 0 || grammar->getGrammarType() != Grammar::SchemaGrammarType) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::GrammarNotFound, uriStr);
|
|
return;
|
|
}
|
|
|
|
refAttDef = (SchemaAttDef*) ((SchemaGrammar*) grammar)->getAttributeDeclRegistry()->get(localPart);
|
|
|
|
if (!refAttDef) {
|
|
|
|
SchemaInfo* impInfo = fSchemaInfo->getImportInfo(attURI);
|
|
|
|
if (!impInfo || impInfo->getProcessed()) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TopLevelAttributeNotFound, refName);
|
|
return;
|
|
}
|
|
|
|
infoType = SchemaInfo::IMPORT;
|
|
restoreSchemaInfo(impInfo, infoType);
|
|
}
|
|
}
|
|
|
|
// if Global attribute registry does not contain the ref attribute, get
|
|
// the referred attribute declaration and traverse it.
|
|
if (!refAttDef) {
|
|
|
|
if (fAttributeDeclRegistry->containsKey(localPart) == false) {
|
|
|
|
DOMElement* referredAttribute = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_Attribute,
|
|
SchemaSymbols::fgELT_ATTRIBUTE, localPart, &fSchemaInfo);
|
|
|
|
if (referredAttribute != 0) {
|
|
traverseAttributeDecl(referredAttribute, 0, true);
|
|
}
|
|
}
|
|
|
|
refAttDef = (SchemaAttDef*) fAttributeDeclRegistry->get(localPart);
|
|
}
|
|
|
|
// restore schema information, if necessary
|
|
if (fSchemaInfo != saveInfo) {
|
|
restoreSchemaInfo(saveInfo, infoType, saveScope);
|
|
}
|
|
|
|
if (!refAttDef) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TopLevelAttributeNotFound, refName);
|
|
return;
|
|
}
|
|
|
|
XMLAttDef::DefAttTypes refAttDefType = refAttDef->getDefaultType();
|
|
const XMLCh* refAttValue = refAttDef->getValue();
|
|
bool invalidAttUse = false;
|
|
|
|
if (refAttDefType == XMLAttDef::Fixed &&
|
|
(defaultVal || (fixedVal && !XMLString::equals(fixedVal, refAttValue)))) {
|
|
|
|
invalidAttUse = true;
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttUseCorrect, refName);
|
|
}
|
|
|
|
DatatypeValidator* attDV = refAttDef->getDatatypeValidator();
|
|
|
|
//check for multiple attributes with type derived from ID
|
|
if (attDV && attDV->getType() == DatatypeValidator::ID) {
|
|
|
|
if (fCurrentAttGroupInfo) {
|
|
|
|
if (fCurrentAttGroupInfo->containsTypeWithId()) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttGrpPropCorrect3, refName);
|
|
return;
|
|
}
|
|
|
|
fCurrentAttGroupInfo->setTypeWithId(true);
|
|
}
|
|
else {
|
|
|
|
if (typeInfo->containsAttWithTypeId()) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttDeclPropCorrect5, refName);
|
|
return;
|
|
}
|
|
|
|
typeInfo->setAttWithTypeId(true);
|
|
}
|
|
}
|
|
|
|
bool required = XMLString::equals(useAttr,SchemaSymbols::fgATTVAL_REQUIRED);
|
|
bool prohibited = XMLString::equals(useAttr,SchemaSymbols::fgATTVAL_PROHIBITED);
|
|
QName* attQName = refAttDef->getAttName();
|
|
SchemaAttDef* attDef = new (fGrammarPoolMemoryManager) SchemaAttDef(attQName->getPrefix(),
|
|
attQName->getLocalPart(),
|
|
attQName->getURI(),
|
|
refAttValue,
|
|
refAttDef->getType(),
|
|
refAttDefType,
|
|
0, fGrammarPoolMemoryManager);
|
|
|
|
attDef->setBaseAttDecl(refAttDef);
|
|
attDef->setPSVIScope(PSVIDefs::SCP_GLOBAL);
|
|
|
|
if (refAttDefType == XMLAttDef::Fixed) {
|
|
if (required && !invalidAttUse) {
|
|
attDef->setDefaultType(XMLAttDef::Required_And_Fixed);
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (prohibited) {
|
|
attDef->setDefaultType(XMLAttDef::Prohibited);
|
|
}
|
|
else {
|
|
|
|
const XMLCh* valueConstraint = defaultVal;
|
|
|
|
if (required){
|
|
|
|
if (fixedVal) {
|
|
|
|
attDef->setDefaultType(XMLAttDef::Required_And_Fixed);
|
|
valueConstraint = fixedVal;
|
|
}
|
|
else {
|
|
attDef->setDefaultType(XMLAttDef::Required);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (fixedVal) {
|
|
attDef->setDefaultType(XMLAttDef::Fixed);
|
|
valueConstraint = fixedVal;
|
|
}
|
|
else if (defaultVal) {
|
|
attDef->setDefaultType(XMLAttDef::Default);
|
|
}
|
|
}
|
|
|
|
if (valueConstraint) {
|
|
|
|
// validate content of value constraint
|
|
if (attDV) {
|
|
|
|
if (attDV->getType() == DatatypeValidator::ID) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttDeclPropCorrect3, refName);
|
|
}
|
|
else {
|
|
try {
|
|
attDV->validate(valueConstraint
|
|
, fSchemaInfo->getValidationContext()
|
|
, fMemoryManager);
|
|
}
|
|
catch(const XMLException& excep) {
|
|
reportSchemaError(elem, excep);
|
|
}
|
|
catch(const OutOfMemoryException&)
|
|
{
|
|
throw;
|
|
}
|
|
catch (...) {
|
|
reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::DatatypeValidationFailure, valueConstraint);
|
|
}
|
|
}
|
|
}
|
|
|
|
attDef->setValue(valueConstraint);
|
|
}
|
|
}
|
|
}
|
|
|
|
attDef->setDatatypeValidator(attDV);
|
|
|
|
bool toClone = false;
|
|
|
|
if (typeInfo) {
|
|
|
|
toClone = true;
|
|
typeInfo->addAttDef(attDef);
|
|
}
|
|
|
|
if (fCurrentAttGroupInfo) {
|
|
fCurrentAttGroupInfo->addAttDef(attDef, toClone);
|
|
}
|
|
}
|
|
|
|
|
|
int TraverseSchema::checkMinMax(ContentSpecNode* const specNode,
|
|
const DOMElement* const elem,
|
|
const int allContextFlag) {
|
|
|
|
int minOccurs = 1;
|
|
int maxOccurs = 1;
|
|
const XMLCh* minOccursStr = getElementAttValue(elem, SchemaSymbols::fgATT_MINOCCURS, DatatypeValidator::Decimal);
|
|
const XMLCh* maxOccursStr = getElementAttValue(elem, SchemaSymbols::fgATT_MAXOCCURS, DatatypeValidator::Decimal);
|
|
|
|
if (!minOccursStr || !*minOccursStr) {
|
|
if (specNode)
|
|
minOccurs = specNode->getMinOccurs();
|
|
}
|
|
else {
|
|
try {
|
|
minOccurs = XMLString::parseInt(minOccursStr, fMemoryManager);
|
|
}
|
|
catch(const NumberFormatException& e)
|
|
{
|
|
// REVISIT: report a warning that we replaced a number too big?
|
|
if(e.getCode()==XMLExcepts::Str_ConvertOverflow)
|
|
minOccurs = 500;
|
|
else
|
|
minOccurs = 1;
|
|
}
|
|
catch(const OutOfMemoryException&)
|
|
{
|
|
throw;
|
|
}
|
|
|
|
if (specNode)
|
|
specNode->setMinOccurs(minOccurs);
|
|
}
|
|
|
|
bool isMaxUnbounded = XMLString::equals(maxOccursStr, fgUnbounded);
|
|
|
|
if (isMaxUnbounded) {
|
|
maxOccurs = SchemaSymbols::XSD_UNBOUNDED;
|
|
if (specNode)
|
|
specNode->setMaxOccurs(maxOccurs);
|
|
}
|
|
else {
|
|
if (!maxOccursStr || !*maxOccursStr) {
|
|
if (specNode)
|
|
maxOccurs = specNode->getMaxOccurs();
|
|
}
|
|
else {
|
|
try {
|
|
maxOccurs = XMLString::parseInt(maxOccursStr, fMemoryManager);
|
|
}
|
|
catch(const NumberFormatException& e)
|
|
{
|
|
// REVISIT: report a warning that we replaced a number too big?
|
|
if(e.getCode()==XMLExcepts::Str_ConvertOverflow && minOccurs < 500)
|
|
maxOccurs = 500;
|
|
else
|
|
maxOccurs = minOccurs;
|
|
}
|
|
catch(const OutOfMemoryException&)
|
|
{
|
|
throw;
|
|
}
|
|
|
|
if (specNode)
|
|
specNode->setMaxOccurs(maxOccurs);
|
|
}
|
|
}
|
|
|
|
if (minOccurs == 0 && maxOccurs == 0){
|
|
return minOccurs;
|
|
}
|
|
|
|
// Constraint checking for min/max value
|
|
if (!isMaxUnbounded) {
|
|
|
|
XMLCh tmpMinStr[128];
|
|
XMLCh tmpMaxStr[128];
|
|
|
|
XMLString::binToText(minOccurs, tmpMinStr, 127, 10, fMemoryManager);
|
|
XMLString::binToText(maxOccurs, tmpMaxStr, 127, 10, fMemoryManager);
|
|
|
|
if (maxOccurs < 1) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidAttValue,
|
|
tmpMaxStr, SchemaSymbols::fgATT_MAXOCCURS);
|
|
if (specNode)
|
|
specNode->setMaxOccurs(minOccurs);
|
|
}
|
|
else if (maxOccurs < minOccurs) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidMin2MaxOccurs,
|
|
tmpMinStr, tmpMaxStr);
|
|
if (specNode)
|
|
specNode->setMaxOccurs(minOccurs);
|
|
}
|
|
}
|
|
|
|
// Constraint checking for 'all' content
|
|
bool isAllElement = (allContextFlag == All_Element);
|
|
bool isAllGroup = (allContextFlag == All_Group);
|
|
bool isGroupRefAll = (allContextFlag == Group_Ref_With_All);
|
|
|
|
if (isAllElement || isAllGroup || isGroupRefAll) {
|
|
|
|
if (maxOccurs != 1 || minOccurs > 1) {
|
|
|
|
// set back correct value in order to carry on
|
|
if (specNode) {
|
|
|
|
specNode->setMaxOccurs(1);
|
|
|
|
if (minOccurs > 1)
|
|
specNode->setMinOccurs(1);
|
|
}
|
|
|
|
if (isAllElement) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadMinMaxAllElem);
|
|
}
|
|
else {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadMinMaxAllCT);
|
|
}
|
|
}
|
|
}
|
|
return minOccurs;
|
|
}
|
|
|
|
|
|
void TraverseSchema::processComplexContent(const DOMElement* const ctElem,
|
|
const XMLCh* const typeName,
|
|
const DOMElement* const childElem,
|
|
ComplexTypeInfo* const typeInfo,
|
|
const XMLCh* const baseLocalPart,
|
|
const bool isMixed,
|
|
const bool isBaseAnyType) {
|
|
|
|
NamespaceScopeManager nsMgr(childElem, fSchemaInfo, this);
|
|
|
|
Janitor<ContentSpecNode> specNodeJan(0);
|
|
ContentSpecNode* specNode = specNodeJan.get();
|
|
const DOMElement* attrNode = 0;
|
|
int typeDerivedBy = typeInfo->getDerivedBy();
|
|
ComplexTypeInfo* baseTypeInfo = typeInfo->getBaseComplexTypeInfo();
|
|
int baseContentType = (baseTypeInfo) ? baseTypeInfo->getContentType() : SchemaElementDecl::Empty;
|
|
|
|
if (baseTypeInfo) {
|
|
|
|
if (typeDerivedBy == SchemaSymbols::XSD_RESTRICTION) {
|
|
|
|
// check to see if the baseType permits derivation by restriction
|
|
if((baseTypeInfo->getFinalSet() & typeDerivedBy) != 0) {
|
|
|
|
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::ForbiddenDerivationByRestriction,
|
|
baseLocalPart);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
}
|
|
else {
|
|
|
|
// check to see if the baseType permits derivation by extension
|
|
if((baseTypeInfo->getFinalSet() & typeDerivedBy) != 0) {
|
|
|
|
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::ForbiddenDerivationByExtension, baseLocalPart);
|
|
throw TraverseSchema::InvalidComplexTypeInfo; // REVISIT - should we continue
|
|
}
|
|
|
|
processElements(ctElem, baseTypeInfo, typeInfo);
|
|
}
|
|
}
|
|
|
|
bool effectiveContent_hasChild = false;
|
|
|
|
if (childElem != 0) {
|
|
|
|
fCircularCheckIndex = fCurrentTypeNameStack->size();
|
|
|
|
// --------------------------------------------------------------------
|
|
// GROUP, ALL, SEQUENCE or CHOICE, followed by attributes, if specified.
|
|
// Note that it's possible that only attributes are specified.
|
|
// --------------------------------------------------------------------
|
|
const XMLCh* childName = childElem->getLocalName();
|
|
|
|
if (XMLString::equals(childName, SchemaSymbols::fgELT_GROUP)) {
|
|
|
|
XercesGroupInfo* grpInfo = traverseGroupDecl(childElem, false);
|
|
|
|
if (grpInfo) {
|
|
|
|
ContentSpecNode* const groupSpecNode = grpInfo->getContentSpec();
|
|
|
|
if (groupSpecNode) {
|
|
|
|
int contentContext = groupSpecNode->hasAllContent() ? Group_Ref_With_All : Not_All_Context;
|
|
specNodeJan.reset(new (fGrammarPoolMemoryManager) ContentSpecNode(*groupSpecNode));
|
|
specNode = specNodeJan.get();
|
|
checkMinMax(specNode, childElem, contentContext);
|
|
}
|
|
}
|
|
|
|
attrNode = XUtil::getNextSiblingElement(childElem);
|
|
|
|
}
|
|
else if (XMLString::equals(childName, SchemaSymbols::fgELT_SEQUENCE)) {
|
|
|
|
specNodeJan.reset(traverseChoiceSequence(childElem, ContentSpecNode::Sequence, effectiveContent_hasChild));
|
|
specNode = specNodeJan.get();
|
|
checkMinMax(specNode, childElem);
|
|
attrNode = XUtil::getNextSiblingElement(childElem);
|
|
}
|
|
else if (XMLString::equals(childName, SchemaSymbols::fgELT_CHOICE)) {
|
|
|
|
specNodeJan.reset(traverseChoiceSequence(childElem, ContentSpecNode::Choice, effectiveContent_hasChild));
|
|
specNode = specNodeJan.get();
|
|
int minOccurs = checkMinMax(specNode, childElem);
|
|
if (!effectiveContent_hasChild && minOccurs != 0) {
|
|
effectiveContent_hasChild = true;
|
|
}
|
|
|
|
attrNode = XUtil::getNextSiblingElement(childElem);
|
|
}
|
|
else if (XMLString::equals(childName, SchemaSymbols::fgELT_ALL)) {
|
|
|
|
specNodeJan.reset(traverseAll(childElem, effectiveContent_hasChild));
|
|
specNode = specNodeJan.get();
|
|
checkMinMax(specNode, childElem, All_Group);
|
|
attrNode = XUtil::getNextSiblingElement(childElem);
|
|
}
|
|
else if (isAttrOrAttrGroup(childElem)) {
|
|
// reset the contentType
|
|
typeInfo->setContentType(SchemaElementDecl::Any);
|
|
attrNode = childElem;
|
|
}
|
|
else {
|
|
reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInComplexType, childName);
|
|
}
|
|
}
|
|
|
|
typeInfo->setContentSpec(specNode);
|
|
typeInfo->setAdoptContentSpec(true);
|
|
specNodeJan.release();
|
|
bool specNodeWasNull = false;
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Merge in information from base, if it exists
|
|
// -----------------------------------------------------------------------
|
|
if (baseTypeInfo) {
|
|
|
|
ContentSpecNode* baseSpecNode = baseTypeInfo->getContentSpec();
|
|
|
|
if (typeDerivedBy == SchemaSymbols::XSD_RESTRICTION) {
|
|
|
|
//check derivation valid - content type is empty (5.2)
|
|
if (!typeInfo->getContentSpec()) {
|
|
|
|
if (baseContentType != SchemaElementDecl::Empty
|
|
&& !emptiableParticle(baseSpecNode)) {
|
|
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::EmptyComplexRestrictionDerivation);
|
|
}
|
|
}
|
|
|
|
// Delay particle constraint checking (5.3) until we have processed
|
|
// the whole schema.
|
|
}
|
|
else {
|
|
|
|
// Compose the final content model by concatenating the base and
|
|
// the current in sequence
|
|
if (!specNode) {
|
|
specNodeWasNull = true;
|
|
if (isMixed) {
|
|
if (baseSpecNode && baseSpecNode->hasAllContent()) {
|
|
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::NotAllContent);
|
|
throw TraverseSchema::InvalidComplexTypeInfo; // REVISIT - should we continue
|
|
}
|
|
}
|
|
if (baseSpecNode) {
|
|
specNodeJan.reset(new (fGrammarPoolMemoryManager) ContentSpecNode(*baseSpecNode));
|
|
specNode = specNodeJan.get();
|
|
typeInfo->setContentSpec(specNode);
|
|
typeInfo->setAdoptContentSpec(true);
|
|
specNodeJan.release();
|
|
}
|
|
}
|
|
else if (baseSpecNode) {
|
|
|
|
if (specNode->hasAllContent() || baseSpecNode->hasAllContent()) {
|
|
|
|
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::NotAllContent);
|
|
throw TraverseSchema::InvalidComplexTypeInfo; // REVISIT - should we continue
|
|
}
|
|
|
|
// Check for derivation valid (extension) - 1.4.3.2.2.1
|
|
if ((isMixed && baseContentType == SchemaElementDecl::Children)
|
|
|| (!isMixed && baseContentType != SchemaElementDecl::Children)) {
|
|
|
|
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::MixedOrElementOnly, baseLocalPart, typeName);
|
|
throw TraverseSchema::InvalidComplexTypeInfo; //REVISIT - should we continue
|
|
}
|
|
|
|
typeInfo->setAdoptContentSpec(false);
|
|
typeInfo->setContentSpec
|
|
(
|
|
new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
ContentSpecNode::ModelGroupSequence
|
|
, new (fGrammarPoolMemoryManager) ContentSpecNode(*baseSpecNode)
|
|
, specNode
|
|
, true
|
|
, true
|
|
, fGrammarPoolMemoryManager
|
|
)
|
|
);
|
|
typeInfo->setAdoptContentSpec(true);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
typeInfo->setDerivedBy(0);
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Set the content type
|
|
// -------------------------------------------------------------
|
|
if (isBaseAnyType && typeDerivedBy == SchemaSymbols::XSD_EXTENSION) {
|
|
|
|
ContentSpecNode* anySpecNode = new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
new (fGrammarPoolMemoryManager) QName
|
|
(
|
|
XMLUni::fgZeroLenString
|
|
, XMLUni::fgZeroLenString
|
|
, fEmptyNamespaceURI, fGrammarPoolMemoryManager
|
|
)
|
|
, false
|
|
, fGrammarPoolMemoryManager
|
|
);
|
|
|
|
anySpecNode->setType(ContentSpecNode::Any_Lax);
|
|
anySpecNode->setMinOccurs(0);
|
|
anySpecNode->setMaxOccurs(SchemaSymbols::XSD_UNBOUNDED);
|
|
|
|
if (!specNode) {
|
|
typeInfo->setContentSpec(anySpecNode);
|
|
typeInfo->setDerivedBy(typeDerivedBy);
|
|
}
|
|
else {
|
|
|
|
typeInfo->setAdoptContentSpec(false);
|
|
typeInfo->setContentSpec
|
|
(
|
|
new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
ContentSpecNode::ModelGroupSequence
|
|
, anySpecNode
|
|
, specNode
|
|
, true
|
|
, true
|
|
, fGrammarPoolMemoryManager
|
|
)
|
|
);
|
|
typeInfo->setAdoptContentSpec(true);
|
|
|
|
if (!isMixed) {
|
|
|
|
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::MixedOrElementOnly, baseLocalPart, typeName);
|
|
throw TraverseSchema::InvalidComplexTypeInfo; //REVISIT - should we continue
|
|
}
|
|
}
|
|
|
|
typeInfo->setContentType(SchemaElementDecl::Mixed_Complex);
|
|
}
|
|
else if (isMixed) {
|
|
|
|
if (specNode != 0) {
|
|
typeInfo->setContentType(SchemaElementDecl::Mixed_Complex);
|
|
}
|
|
else {
|
|
// add #PCDATA leaf and set its minOccurs to 0
|
|
ContentSpecNode* pcdataNode = new (fGrammarPoolMemoryManager) ContentSpecNode
|
|
(
|
|
new (fGrammarPoolMemoryManager) QName
|
|
(
|
|
XMLUni::fgZeroLenString
|
|
, XMLUni::fgZeroLenString
|
|
, XMLElementDecl::fgPCDataElemId
|
|
, fGrammarPoolMemoryManager
|
|
)
|
|
, false
|
|
, fGrammarPoolMemoryManager
|
|
);
|
|
|
|
pcdataNode->setMinOccurs(0);
|
|
typeInfo->setContentSpec(pcdataNode);
|
|
typeInfo->setAdoptContentSpec(true);
|
|
typeInfo->setContentType(SchemaElementDecl::Mixed_Simple);
|
|
}
|
|
}
|
|
else if (specNodeWasNull &&
|
|
(typeDerivedBy == SchemaSymbols::XSD_EXTENSION) &&
|
|
baseTypeInfo) {
|
|
typeInfo->setBaseDatatypeValidator(baseTypeInfo->getBaseDatatypeValidator());
|
|
typeInfo->setDatatypeValidator(baseTypeInfo->getDatatypeValidator());
|
|
typeInfo->setContentType(baseTypeInfo->getContentType());
|
|
}
|
|
else if (typeInfo->getContentSpec() == 0) {
|
|
if (!effectiveContent_hasChild) {
|
|
typeInfo->setContentType(SchemaElementDecl::Empty);
|
|
}
|
|
else {
|
|
typeInfo->setContentType(SchemaElementDecl::ElementOnlyEmpty);
|
|
}
|
|
}
|
|
else {
|
|
typeInfo->setContentType(SchemaElementDecl::Children);
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Now, check attributes and handle
|
|
// -------------------------------------------------------------
|
|
if (attrNode != 0) {
|
|
|
|
if (!isAttrOrAttrGroup(attrNode)) {
|
|
reportSchemaError(attrNode, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInComplexType,
|
|
attrNode->getLocalName());
|
|
}
|
|
else {
|
|
processAttributes(ctElem, attrNode, typeInfo, isBaseAnyType);
|
|
}
|
|
}
|
|
else if (baseTypeInfo != 0 || isBaseAnyType) {
|
|
processAttributes(ctElem, 0, typeInfo, isBaseAnyType);
|
|
}
|
|
}
|
|
|
|
|
|
void TraverseSchema::processBaseTypeInfo(const DOMElement* const elem,
|
|
const XMLCh* const baseName,
|
|
const XMLCh* const localPart,
|
|
const XMLCh* const uriStr,
|
|
ComplexTypeInfo* const typeInfo) {
|
|
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
ComplexTypeInfo* baseComplexTypeInfo = 0;
|
|
DatatypeValidator* baseDTValidator = 0;
|
|
SchemaInfo::ListType infoType = SchemaInfo::INCLUDE;
|
|
unsigned int saveScope = fCurrentScope;
|
|
|
|
// check if the base type is from another schema
|
|
if (!XMLString::equals(uriStr, fTargetNSURIString)) {
|
|
|
|
// check for datatype validator if it's schema for schema URI
|
|
if (XMLString::equals(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {
|
|
|
|
baseDTValidator = getDatatypeValidator(uriStr, localPart);
|
|
|
|
if (!baseDTValidator) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BaseTypeNotFound, baseName);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
}
|
|
else {
|
|
|
|
// Make sure that we have an explicit import statement.
|
|
// Clause 4 of Schema Representation Constraint:
|
|
// http://www.w3.org/TR/xmlschema-1/#src-resolve
|
|
unsigned int uriId = fURIStringPool->addOrFind(uriStr);
|
|
|
|
if (!isImportingNS(uriId)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, uriStr);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
|
|
baseComplexTypeInfo = getTypeInfoFromNS(elem, uriStr, localPart);
|
|
|
|
if (!baseComplexTypeInfo) {
|
|
|
|
baseDTValidator = getDatatypeValidator(uriStr, localPart);
|
|
|
|
if (!baseDTValidator)
|
|
{
|
|
SchemaInfo* impInfo = fSchemaInfo->getImportInfo(fURIStringPool->addOrFind(uriStr));
|
|
|
|
if (!impInfo || impInfo->getProcessed())
|
|
{
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BaseTypeNotFound, baseName);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
|
|
infoType = SchemaInfo::IMPORT;
|
|
restoreSchemaInfo(impInfo, infoType);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
fBuffer.set(uriStr);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(localPart);
|
|
|
|
// assume the base is a complexType and try to locate the base type first
|
|
const XMLCh* fullBaseName = fBuffer.getRawBuffer();
|
|
baseComplexTypeInfo = fComplexTypeRegistry->get(fullBaseName);
|
|
|
|
// Circular check
|
|
if (baseComplexTypeInfo) {
|
|
|
|
if (fCurrentTypeNameStack->containsElement(fStringPool->addOrFind(fullBaseName), fCircularCheckIndex)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoCircularDefinition, fullBaseName);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
else if (fCurrentTypeNameStack->containsElement(fStringPool->addOrFind(fullBaseName))) {
|
|
|
|
typeInfo->setBaseComplexTypeInfo(baseComplexTypeInfo);
|
|
throw TraverseSchema::RecursingElement;
|
|
}
|
|
else if (baseComplexTypeInfo->getPreprocessed()) {
|
|
baseComplexTypeInfo = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if not found, 2 possibilities:
|
|
// 1: ComplexType in question has not been compiled yet;
|
|
// 2: base is SimpleType;
|
|
if (!baseComplexTypeInfo && !baseDTValidator) {
|
|
|
|
baseDTValidator = getDatatypeValidator(uriStr, localPart);
|
|
|
|
if (baseDTValidator == 0) {
|
|
|
|
DOMElement* baseTypeNode = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_ComplexType,
|
|
SchemaSymbols::fgELT_COMPLEXTYPE, localPart, &fSchemaInfo);
|
|
|
|
if (baseTypeNode != 0) {
|
|
|
|
int baseTypeSymbol = traverseComplexTypeDecl(baseTypeNode);
|
|
baseComplexTypeInfo = fComplexTypeRegistry->get(fStringPool->getValueForId(baseTypeSymbol));
|
|
}
|
|
else {
|
|
|
|
baseTypeNode = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_SimpleType,
|
|
SchemaSymbols::fgELT_SIMPLETYPE, localPart, &fSchemaInfo);
|
|
|
|
if (baseTypeNode != 0) {
|
|
|
|
baseDTValidator = traverseSimpleTypeDecl(baseTypeNode);
|
|
|
|
if (baseDTValidator == 0) {
|
|
|
|
// restore schema information, if necessary
|
|
if (saveInfo != fSchemaInfo) {
|
|
restoreSchemaInfo(saveInfo, infoType, saveScope);
|
|
}
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, uriStr, localPart, uriStr);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
}
|
|
else {
|
|
|
|
// restore schema information, if necessary
|
|
if (saveInfo != fSchemaInfo) {
|
|
restoreSchemaInfo(saveInfo, infoType, saveScope);
|
|
}
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BaseTypeNotFound, baseName);
|
|
throw TraverseSchema::InvalidComplexTypeInfo;
|
|
}
|
|
}
|
|
}
|
|
} // end if
|
|
|
|
// restore schema information, if necessary
|
|
if (saveInfo != fSchemaInfo) {
|
|
restoreSchemaInfo(saveInfo, infoType, saveScope);
|
|
}
|
|
|
|
typeInfo->setBaseComplexTypeInfo(baseComplexTypeInfo);
|
|
typeInfo->setBaseDatatypeValidator(baseDTValidator);
|
|
}
|
|
|
|
|
|
ComplexTypeInfo* TraverseSchema::getTypeInfoFromNS(const DOMElement* const elem,
|
|
const XMLCh* const uriStr,
|
|
const XMLCh* const localPart)
|
|
{
|
|
|
|
Grammar* grammar = fGrammarResolver->getGrammar(uriStr);
|
|
|
|
if (grammar != 0 && grammar->getGrammarType() == Grammar::SchemaGrammarType) {
|
|
|
|
fBuffer.set(uriStr);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(localPart);
|
|
|
|
ComplexTypeInfo* typeInfo =
|
|
((SchemaGrammar*)grammar)->getComplexTypeRegistry()->get(fBuffer.getRawBuffer());
|
|
|
|
return typeInfo;
|
|
}
|
|
else {
|
|
reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::GrammarNotFound, uriStr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void TraverseSchema::processAttributes(const DOMElement* const elem,
|
|
const DOMElement* const attElem,
|
|
ComplexTypeInfo* const typeInfo,
|
|
const bool isBaseAnyType) {
|
|
|
|
// If we do not have a complexTypeInfo, then what is the point of
|
|
// processing.
|
|
if (typeInfo == 0) {
|
|
return;
|
|
}
|
|
|
|
ComplexTypeInfo* baseTypeInfo = typeInfo->getBaseComplexTypeInfo();
|
|
if (baseTypeInfo && baseTypeInfo->getPreprocessed())
|
|
throw TraverseSchema::RecursingElement;
|
|
|
|
const DOMElement* child = attElem;
|
|
SchemaAttDef* attWildCard = 0;
|
|
Janitor<SchemaAttDef> janAttWildCard(0);
|
|
XercesAttGroupInfo* attGroupInfo = 0;
|
|
ValueVectorOf<XercesAttGroupInfo*> attGroupList(4, fGrammarPoolMemoryManager);
|
|
|
|
for (; child != 0; child = XUtil::getNextSiblingElement(child)) {
|
|
|
|
const XMLCh* childName = child->getLocalName();
|
|
|
|
if (XMLString::equals(childName, SchemaSymbols::fgELT_ATTRIBUTE)) {
|
|
if(attWildCard)
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::AnyAttributeBeforeAttribute);
|
|
|
|
traverseAttributeDecl(child, typeInfo);
|
|
}
|
|
else if (XMLString::equals(childName, SchemaSymbols::fgELT_ATTRIBUTEGROUP)) {
|
|
if(attWildCard)
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::AnyAttributeBeforeAttribute);
|
|
|
|
attGroupInfo = traverseAttributeGroupDecl(child, typeInfo);
|
|
if (attGroupInfo && !attGroupList.containsElement(attGroupInfo)) {
|
|
attGroupList.addElement(attGroupInfo);
|
|
}
|
|
}
|
|
else if (XMLString::equals(childName, SchemaSymbols::fgELT_ANYATTRIBUTE) ) {
|
|
if(attWildCard)
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAnyAttribute);
|
|
|
|
attWildCard = traverseAnyAttribute(child);
|
|
janAttWildCard.reset(attWildCard);
|
|
}
|
|
else {
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInComplexType, childName);
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Handle wild card/any attribute
|
|
// -------------------------------------------------------------
|
|
int derivedBy = typeInfo->getDerivedBy();
|
|
XMLSize_t attGroupListSize = attGroupList.size();
|
|
|
|
if (attGroupListSize) {
|
|
|
|
SchemaAttDef* completeWildCard = 0;
|
|
Janitor<SchemaAttDef> janCompleteWildCard(0);
|
|
XMLAttDef::DefAttTypes defAttType = XMLAttDef::Default;
|
|
bool defAttTypeSet = false;
|
|
|
|
for (XMLSize_t i=0; i < attGroupListSize; i++) {
|
|
|
|
attGroupInfo = attGroupList.elementAt(i);
|
|
XMLSize_t anyAttCount = attGroupInfo->anyAttributeCount();
|
|
|
|
if (anyAttCount) {
|
|
|
|
if (!defAttTypeSet) {
|
|
|
|
defAttType = (attWildCard) ? attWildCard->getDefaultType()
|
|
: attGroupInfo->anyAttributeAt(0)->getDefaultType();
|
|
defAttTypeSet = true;
|
|
}
|
|
|
|
SchemaAttDef* attGroupWildCard = attGroupInfo->getCompleteWildCard();
|
|
if (completeWildCard) {
|
|
attWildCardIntersection(completeWildCard, attGroupWildCard);
|
|
}
|
|
else {
|
|
completeWildCard = new (fGrammarPoolMemoryManager) SchemaAttDef(attGroupWildCard);
|
|
janCompleteWildCard.reset(completeWildCard);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (completeWildCard) {
|
|
|
|
if (attWildCard) {
|
|
attWildCardIntersection(attWildCard, completeWildCard);
|
|
}
|
|
else {
|
|
|
|
attWildCard = completeWildCard;
|
|
janCompleteWildCard.orphan();
|
|
janAttWildCard.reset(attWildCard);
|
|
}
|
|
|
|
attWildCard->setDefaultType(defAttType);
|
|
}
|
|
}
|
|
|
|
SchemaAttDef* baseAttWildCard = (baseTypeInfo) ? baseTypeInfo->getAttWildCard() : 0;
|
|
Janitor<SchemaAttDef> janBaseAttWildCard(0);
|
|
|
|
if (derivedBy == SchemaSymbols::XSD_EXTENSION) {
|
|
|
|
if (isBaseAnyType) {
|
|
|
|
baseAttWildCard = new (fGrammarPoolMemoryManager) SchemaAttDef(XMLUni::fgZeroLenString,
|
|
XMLUni::fgZeroLenString,
|
|
fEmptyNamespaceURI, XMLAttDef::Any_Any,
|
|
XMLAttDef::ProcessContents_Lax,
|
|
fGrammarPoolMemoryManager);
|
|
janBaseAttWildCard.reset(baseAttWildCard);
|
|
}
|
|
|
|
if (baseAttWildCard && attWildCard) {
|
|
|
|
XMLAttDef::DefAttTypes saveDefType = attWildCard->getDefaultType();
|
|
attWildCardUnion(attWildCard, baseAttWildCard);
|
|
attWildCard->setDefaultType(saveDefType);
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// insert wildcard attribute
|
|
// -------------------------------------------------------------
|
|
if (attWildCard) {
|
|
|
|
typeInfo->setAttWildCard(attWildCard);
|
|
janAttWildCard.orphan();
|
|
|
|
if (attWildCard->getType() == XMLAttDef::AttTypes_Unknown) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NotExpressibleWildCardIntersection);
|
|
}
|
|
}
|
|
else if (baseAttWildCard && derivedBy == SchemaSymbols::XSD_EXTENSION) {
|
|
|
|
if (isBaseAnyType) {
|
|
|
|
typeInfo->setAttWildCard(baseAttWildCard);
|
|
janBaseAttWildCard.orphan();
|
|
}
|
|
else {
|
|
|
|
SchemaAttDef* newWildCard = new (fGrammarPoolMemoryManager) SchemaAttDef(baseAttWildCard);
|
|
typeInfo->setAttWildCard(newWildCard);
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Check attributes derivation OK
|
|
// -------------------------------------------------------------
|
|
bool baseWithAttributes = (baseTypeInfo && baseTypeInfo->hasAttDefs());
|
|
bool childWithAttributes = (typeInfo->hasAttDefs() || typeInfo->getAttWildCard());
|
|
|
|
if (derivedBy == SchemaSymbols::XSD_RESTRICTION && childWithAttributes) {
|
|
|
|
if (!baseWithAttributes && !baseAttWildCard) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_1);
|
|
}
|
|
else {
|
|
checkAttDerivationOK(elem, baseTypeInfo, typeInfo);
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// merge in base type's attribute decls
|
|
// -------------------------------------------------------------
|
|
if (baseTypeInfo && baseTypeInfo->hasAttDefs()) {
|
|
|
|
SchemaAttDefList& baseAttList = (SchemaAttDefList&)
|
|
baseTypeInfo->getAttDefList();
|
|
|
|
for (XMLSize_t i=0; i<baseAttList.getAttDefCount(); i++) {
|
|
|
|
SchemaAttDef& attDef = (SchemaAttDef&) baseAttList.getAttDef(i);
|
|
QName* attName = attDef.getAttName();
|
|
const XMLCh* localPart = attName->getLocalPart();
|
|
|
|
// if found a duplicate, then skip the one from the base type
|
|
if (typeInfo->getAttDef(localPart, attName->getURI()) != 0) {
|
|
|
|
if (derivedBy == SchemaSymbols::XSD_EXTENSION) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttInDerivation, localPart);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (attDef.getDefaultType() != XMLAttDef::Prohibited) {
|
|
|
|
SchemaAttDef* newAttDef = new (fGrammarPoolMemoryManager) SchemaAttDef(attName->getPrefix(),
|
|
attName->getLocalPart(),
|
|
attName->getURI(),
|
|
attDef.getValue(),
|
|
attDef.getType(),
|
|
attDef.getDefaultType(),
|
|
attDef.getEnumeration(),
|
|
fGrammarPoolMemoryManager);
|
|
|
|
newAttDef->setDatatypeValidator(attDef.getDatatypeValidator());
|
|
typeInfo->addAttDef(newAttDef);
|
|
|
|
if (attDef.getBaseAttDecl())
|
|
newAttDef->setBaseAttDecl(attDef.getBaseAttDecl());
|
|
else
|
|
newAttDef->setBaseAttDecl(&attDef);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void TraverseSchema::defaultComplexTypeInfo(ComplexTypeInfo* const typeInfo) {
|
|
|
|
if (typeInfo) {
|
|
|
|
typeInfo->setDerivedBy(0);
|
|
typeInfo->setContentType(SchemaElementDecl::Any);
|
|
typeInfo->setDatatypeValidator(0);
|
|
typeInfo->setContentSpec(0);
|
|
typeInfo->setBaseComplexTypeInfo(0);
|
|
typeInfo->setBaseDatatypeValidator(0);
|
|
}
|
|
}
|
|
|
|
|
|
InputSource* TraverseSchema::resolveSchemaLocation(const XMLCh* const loc,
|
|
const XMLResourceIdentifier::ResourceIdentifierType resourceIdentitiferType,
|
|
const XMLCh* const nameSpace) {
|
|
|
|
// ------------------------------------------------------------------
|
|
// Create an input source
|
|
// ------------------------------------------------------------------
|
|
InputSource* srcToFill = 0;
|
|
XMLCh* normalizedURI = 0;
|
|
if (loc) {
|
|
XMLString::removeChar(loc, 0xFFFF, fBuffer);
|
|
normalizedURI = fBuffer.getRawBuffer();
|
|
}
|
|
|
|
if (fEntityHandler){
|
|
XMLResourceIdentifier resourceIdentifier(resourceIdentitiferType,
|
|
normalizedURI, nameSpace, 0, fSchemaInfo->getCurrentSchemaURL(), fLocator);
|
|
srcToFill = fEntityHandler->resolveEntity(&resourceIdentifier);
|
|
}
|
|
|
|
// If they didn't create a source via the entity resolver, then we
|
|
// have to create one on our own if we have the schemaLocation (with
|
|
// the update resolveEntity accepting nameSpace, a schemImport could
|
|
// pass a null schemaLocation)
|
|
if (!srcToFill && loc) {
|
|
if (fScanner->getDisableDefaultEntityResolution())
|
|
return 0;
|
|
|
|
XMLURL urlTmp(fMemoryManager);
|
|
if ((!urlTmp.setURL(fSchemaInfo->getCurrentSchemaURL(), normalizedURI, urlTmp)) ||
|
|
(urlTmp.isRelative()))
|
|
{
|
|
if (!fScanner->getStandardUriConformant())
|
|
{
|
|
XMLCh* tempURI = XMLString::replicate(normalizedURI, fMemoryManager);
|
|
ArrayJanitor<XMLCh> tempURIName(tempURI, fMemoryManager);
|
|
XMLUri::normalizeURI(tempURI, fBuffer);
|
|
|
|
srcToFill = new (fMemoryManager) LocalFileInputSource
|
|
( fSchemaInfo->getCurrentSchemaURL()
|
|
, fBuffer.getRawBuffer()
|
|
, fMemoryManager
|
|
);
|
|
}
|
|
else
|
|
ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);
|
|
}
|
|
else
|
|
{
|
|
if (fScanner->getStandardUriConformant() && urlTmp.hasInvalidChar())
|
|
ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);
|
|
srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager);
|
|
}
|
|
}
|
|
|
|
return srcToFill;
|
|
}
|
|
|
|
|
|
void TraverseSchema::restoreSchemaInfo(SchemaInfo* const toRestore,
|
|
SchemaInfo::ListType const aListType,
|
|
const unsigned int saveScope) {
|
|
|
|
|
|
if (aListType == SchemaInfo::IMPORT) { // restore grammar info
|
|
|
|
int targetNSURI = toRestore->getTargetNSURI();
|
|
|
|
fSchemaGrammar->setScopeCount (fScopeCount);
|
|
fSchemaGrammar->setAnonTypeCount (fAnonXSTypeCount);
|
|
|
|
fSchemaGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(toRestore->getTargetNSURIString());
|
|
fScopeCount = fSchemaGrammar->getScopeCount ();
|
|
fAnonXSTypeCount = fSchemaGrammar->getAnonTypeCount ();
|
|
|
|
fTargetNSURI = targetNSURI;
|
|
fCurrentScope = saveScope;
|
|
fDatatypeRegistry = fSchemaGrammar->getDatatypeRegistry();
|
|
fTargetNSURIString = fSchemaGrammar->getTargetNamespace();
|
|
fGroupRegistry = fSchemaGrammar->getGroupInfoRegistry();
|
|
fAttGroupRegistry = fSchemaGrammar->getAttGroupInfoRegistry();
|
|
fAttributeDeclRegistry = fSchemaGrammar->getAttributeDeclRegistry();
|
|
fComplexTypeRegistry = fSchemaGrammar->getComplexTypeRegistry();
|
|
fValidSubstitutionGroups = fSchemaGrammar->getValidSubstitutionGroups();
|
|
|
|
}
|
|
|
|
fSchemaInfo = toRestore;
|
|
}
|
|
|
|
|
|
bool
|
|
TraverseSchema::emptiableParticle(const ContentSpecNode* const specNode) {
|
|
|
|
if (!fFullConstraintChecking || !specNode || (specNode->getMinTotalRange() == 0)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void TraverseSchema::checkFixedFacet(const DOMElement* const elem,
|
|
const XMLCh* const facetName,
|
|
const DatatypeValidator* const baseDV,
|
|
unsigned int& flags)
|
|
{
|
|
const XMLCh* fixedFacet = getElementAttValue(elem, SchemaSymbols::fgATT_FIXED);
|
|
|
|
if ((fixedFacet && *fixedFacet) &&
|
|
(XMLString::equals(fixedFacet, SchemaSymbols::fgATTVAL_TRUE)
|
|
|| XMLString::equals(fixedFacet, fgValueOne))) {
|
|
|
|
if (XMLString::equals(SchemaSymbols::fgELT_LENGTH, facetName)) {
|
|
flags |= DatatypeValidator::FACET_LENGTH;
|
|
}
|
|
if (XMLString::equals(SchemaSymbols::fgELT_MINLENGTH, facetName)) {
|
|
flags |= DatatypeValidator::FACET_MINLENGTH;
|
|
}
|
|
else if (XMLString::equals(SchemaSymbols::fgELT_MAXLENGTH, facetName)) {
|
|
flags |= DatatypeValidator::FACET_MAXLENGTH;
|
|
}
|
|
else if (XMLString::equals(SchemaSymbols::fgELT_MAXEXCLUSIVE, facetName)) {
|
|
flags |= DatatypeValidator::FACET_MAXEXCLUSIVE;
|
|
}
|
|
else if (XMLString::equals(SchemaSymbols::fgELT_MAXINCLUSIVE, facetName)) {
|
|
flags |= DatatypeValidator::FACET_MAXINCLUSIVE;
|
|
}
|
|
else if (XMLString::equals(SchemaSymbols::fgELT_MINEXCLUSIVE, facetName)) {
|
|
flags |= DatatypeValidator::FACET_MINEXCLUSIVE;
|
|
}
|
|
else if (XMLString::equals(SchemaSymbols::fgELT_MININCLUSIVE, facetName)) {
|
|
flags |= DatatypeValidator::FACET_MININCLUSIVE;
|
|
}
|
|
else if (XMLString::equals(SchemaSymbols::fgELT_TOTALDIGITS, facetName)) {
|
|
flags |= DatatypeValidator::FACET_TOTALDIGITS;
|
|
}
|
|
else if (XMLString::equals(SchemaSymbols::fgELT_FRACTIONDIGITS, facetName)) {
|
|
flags |= DatatypeValidator::FACET_FRACTIONDIGITS;
|
|
}
|
|
else if ((XMLString::equals(SchemaSymbols::fgELT_WHITESPACE, facetName)) &&
|
|
baseDV->getType() == DatatypeValidator::String) {
|
|
flags |= DatatypeValidator::FACET_WHITESPACE;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
TraverseSchema::buildValidSubstitutionListB(const DOMElement* const elem,
|
|
SchemaElementDecl* const elemDecl,
|
|
SchemaElementDecl* const subsElemDecl) {
|
|
|
|
SchemaElementDecl* chainElemDecl = subsElemDecl->getSubstitutionGroupElem();
|
|
|
|
while (chainElemDecl) {
|
|
|
|
int chainElemURI = chainElemDecl->getURI();
|
|
XMLCh* chainElemName = chainElemDecl->getBaseName();
|
|
ValueVectorOf<SchemaElementDecl*>* validSubsElements =
|
|
fValidSubstitutionGroups->get(chainElemName, chainElemURI);
|
|
|
|
if (!validSubsElements) {
|
|
|
|
if (fTargetNSURI == chainElemURI) {
|
|
break; // an error must have occured
|
|
}
|
|
|
|
SchemaGrammar* aGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(fURIStringPool->getValueForId(chainElemURI));
|
|
|
|
if (!aGrammar)
|
|
break;
|
|
|
|
validSubsElements = aGrammar->getValidSubstitutionGroups()->get(chainElemName, chainElemURI);
|
|
|
|
if (!validSubsElements) {
|
|
break;
|
|
}
|
|
|
|
validSubsElements = new (fGrammarPoolMemoryManager) ValueVectorOf<SchemaElementDecl*>(*validSubsElements);
|
|
fValidSubstitutionGroups->put((void*) chainElemName, chainElemURI, validSubsElements);
|
|
}
|
|
|
|
if (validSubsElements->containsElement(elemDecl) ||
|
|
!isSubstitutionGroupValid(elem, chainElemDecl, elemDecl->getComplexTypeInfo(),
|
|
elemDecl->getDatatypeValidator(), 0, false)) {
|
|
break;
|
|
}
|
|
|
|
validSubsElements->addElement(elemDecl);
|
|
|
|
// update related subs. info in case of circular import
|
|
BaseRefVectorEnumerator<SchemaInfo> importingEnum = fSchemaInfo->getImportingListEnumerator();
|
|
|
|
while (importingEnum.hasMoreElements()) {
|
|
|
|
const SchemaInfo& curRef = importingEnum.nextElement();
|
|
SchemaGrammar* aGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(curRef.getTargetNSURIString());
|
|
ValueVectorOf<SchemaElementDecl*>* subsElemList =
|
|
aGrammar->getValidSubstitutionGroups()->get(chainElemName, chainElemURI);
|
|
|
|
if (subsElemList && !subsElemList->containsElement(elemDecl)) {
|
|
subsElemList->addElement(elemDecl);
|
|
}
|
|
}
|
|
|
|
chainElemDecl = chainElemDecl->getSubstitutionGroupElem();
|
|
}
|
|
}
|
|
|
|
void
|
|
TraverseSchema::buildValidSubstitutionListF(const DOMElement* const elem,
|
|
SchemaElementDecl* const elemDecl,
|
|
SchemaElementDecl* const subsElemDecl) {
|
|
|
|
int elemURI = elemDecl->getURI();
|
|
XMLCh* elemName = elemDecl->getBaseName();
|
|
ValueVectorOf<SchemaElementDecl*>* validSubsElements =fValidSubstitutionGroups->get(elemName, elemURI);
|
|
|
|
if (validSubsElements) {
|
|
|
|
int subsElemURI = subsElemDecl->getURI();
|
|
XMLCh* subsElemName = subsElemDecl->getBaseName();
|
|
ValueVectorOf<SchemaElementDecl*>* validSubs = fValidSubstitutionGroups->get(subsElemName, subsElemURI);
|
|
|
|
if (!validSubs) {
|
|
|
|
if (fTargetNSURI == subsElemURI) {
|
|
return; // an error must have occured
|
|
}
|
|
|
|
SchemaGrammar* aGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(fURIStringPool->getValueForId(subsElemURI));
|
|
|
|
if (!aGrammar)
|
|
return;
|
|
|
|
validSubs = aGrammar->getValidSubstitutionGroups()->get(subsElemName, subsElemURI);
|
|
|
|
if (!validSubs) {
|
|
return;
|
|
}
|
|
|
|
validSubs = new (fGrammarPoolMemoryManager) ValueVectorOf<SchemaElementDecl*>(*validSubs);
|
|
fValidSubstitutionGroups->put((void*) subsElemName, subsElemURI, validSubs);
|
|
}
|
|
|
|
XMLSize_t elemSize = validSubsElements->size();
|
|
for (XMLSize_t i=0; i<elemSize; i++) {
|
|
|
|
SchemaElementDecl* chainElem = validSubsElements->elementAt(i);
|
|
|
|
if (validSubs->containsElement(chainElem)) {
|
|
continue;
|
|
}
|
|
|
|
if (isSubstitutionGroupValid(elem, subsElemDecl, chainElem->getComplexTypeInfo(),
|
|
chainElem->getDatatypeValidator(), 0, false)) {
|
|
validSubs->addElement(chainElem);
|
|
buildValidSubstitutionListB(elem, chainElem, subsElemDecl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TraverseSchema::checkEnumerationRequiredNotation(const DOMElement* const elem,
|
|
const XMLCh* const name,
|
|
const XMLCh* const type) {
|
|
|
|
const XMLCh* localPart = getLocalPart(type);
|
|
|
|
if (XMLString::equals(localPart, XMLUni::fgNotationString)) {
|
|
const XMLCh* prefix = getPrefix(type);
|
|
const XMLCh* typeURI = resolvePrefixToURI(elem, prefix);
|
|
|
|
if (XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNotationType, name);
|
|
}
|
|
}
|
|
}
|
|
|
|
XercesGroupInfo* TraverseSchema::processGroupRef(const DOMElement* const elem,
|
|
const XMLCh* const refName) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
DOMElement* content = checkContent(elem, XUtil::getFirstChildElement(elem), true);
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
if (content != 0) {
|
|
reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::NoContentForRef, SchemaSymbols::fgELT_GROUP);
|
|
}
|
|
|
|
const XMLCh* prefix = getPrefix(refName);
|
|
const XMLCh* localPart = getLocalPart(refName);
|
|
const XMLCh* uriStr = resolvePrefixToURI(elem, prefix);
|
|
|
|
fBuffer.set(uriStr);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(localPart);
|
|
|
|
unsigned int nameIndex = fStringPool->addOrFind(fBuffer.getRawBuffer());
|
|
|
|
if (fCurrentGroupStack->containsElement(nameIndex)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoCircularDefinition, localPart);
|
|
return 0;
|
|
}
|
|
|
|
XercesGroupInfo* groupInfo = 0;
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
SchemaInfo::ListType infoType = SchemaInfo::INCLUDE;
|
|
unsigned int saveScope = fCurrentScope;
|
|
|
|
//if from another target namespace
|
|
if (!XMLString::equals(uriStr, fTargetNSURIString)) {
|
|
|
|
// Make sure that we have an explicit import statement.
|
|
// Clause 4 of Schema Representation Constraint:
|
|
// http://www.w3.org/TR/xmlschema-1/#src-resolve
|
|
unsigned int uriId = fURIStringPool->addOrFind(uriStr);
|
|
|
|
if (!isImportingNS(uriId)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, uriStr);
|
|
return 0;
|
|
}
|
|
|
|
Grammar* aGrammar = fGrammarResolver->getGrammar(uriStr);
|
|
|
|
if (!aGrammar || aGrammar->getGrammarType() != Grammar::SchemaGrammarType) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::GrammarNotFound, uriStr);
|
|
return 0;
|
|
}
|
|
|
|
groupInfo = ((SchemaGrammar*)aGrammar)->getGroupInfoRegistry()->get(fStringPool->getValueForId(nameIndex));
|
|
|
|
if (!groupInfo) {
|
|
|
|
SchemaInfo* impInfo = fSchemaInfo->getImportInfo(fURIStringPool->addOrFind(uriStr));
|
|
|
|
if (!impInfo || impInfo->getProcessed()) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNotFound,
|
|
SchemaSymbols::fgELT_GROUP, uriStr, localPart);
|
|
return 0;
|
|
}
|
|
|
|
infoType = SchemaInfo::IMPORT;
|
|
restoreSchemaInfo(impInfo, infoType);
|
|
}
|
|
}
|
|
else {
|
|
groupInfo = fGroupRegistry->get(fStringPool->getValueForId(nameIndex));
|
|
}
|
|
|
|
if (!groupInfo) {
|
|
|
|
DOMElement* groupElem = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_Group,
|
|
SchemaSymbols::fgELT_GROUP, localPart, &fSchemaInfo);
|
|
|
|
if (groupElem != 0) {
|
|
|
|
groupInfo = traverseGroupDecl(groupElem);
|
|
|
|
// restore schema information
|
|
restoreSchemaInfo(saveInfo, infoType, saveScope);
|
|
|
|
if (groupInfo && (fCurrentGroupInfo || infoType == SchemaInfo::IMPORT)) {
|
|
copyGroupElements(elem, groupInfo, fCurrentGroupInfo,
|
|
(infoType == SchemaInfo::IMPORT) ? fCurrentComplexType : 0);
|
|
}
|
|
|
|
return groupInfo;
|
|
}
|
|
else {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNotFound,
|
|
SchemaSymbols::fgELT_GROUP, uriStr, localPart);
|
|
}
|
|
|
|
// restore schema information, if necessary
|
|
if (saveInfo != fSchemaInfo) {
|
|
restoreSchemaInfo(saveInfo, infoType, saveScope);
|
|
}
|
|
}
|
|
else {
|
|
copyGroupElements(elem, groupInfo, fCurrentGroupInfo, fCurrentComplexType);
|
|
}
|
|
|
|
return groupInfo;
|
|
}
|
|
|
|
|
|
XercesAttGroupInfo*
|
|
TraverseSchema::processAttributeGroupRef(const DOMElement* const elem,
|
|
const XMLCh* const refName,
|
|
ComplexTypeInfo* const typeInfo) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
if (checkContent(elem, XUtil::getFirstChildElement(elem), true) != 0) {
|
|
reportSchemaError(elem ,XMLUni::fgValidityDomain, XMLValid::NoContentForRef, SchemaSymbols::fgELT_ATTRIBUTEGROUP);
|
|
}
|
|
|
|
Janitor<XSAnnotation> janAnnot(fAnnotation);
|
|
const XMLCh* prefix = getPrefix(refName);
|
|
const XMLCh* localPart = getLocalPart(refName);
|
|
const XMLCh* uriStr = resolvePrefixToURI(elem, prefix);
|
|
XercesAttGroupInfo* attGroupInfo = 0;
|
|
SchemaInfo* saveInfo = fSchemaInfo;
|
|
SchemaInfo::ListType infoType = SchemaInfo::INCLUDE;
|
|
unsigned int saveScope = fCurrentScope;
|
|
|
|
if (!XMLString::equals(uriStr, fTargetNSURIString)) {
|
|
|
|
// Make sure that we have an explicit import statement.
|
|
// Clause 4 of Schema Representation Constraint:
|
|
// http://www.w3.org/TR/xmlschema-1/#src-resolve
|
|
unsigned int uriId = fURIStringPool->addOrFind(uriStr);
|
|
|
|
if (!isImportingNS(uriId)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, uriStr);
|
|
return 0;
|
|
}
|
|
|
|
attGroupInfo = traverseAttributeGroupDeclNS(elem, uriStr, localPart);
|
|
|
|
if (!attGroupInfo) {
|
|
SchemaInfo* impInfo = fSchemaInfo->getImportInfo(fURIStringPool->addOrFind(uriStr));
|
|
|
|
if (!impInfo || impInfo->getProcessed()) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNotFound,
|
|
SchemaSymbols::fgELT_ATTRIBUTEGROUP, uriStr, localPart);
|
|
return 0;
|
|
}
|
|
|
|
infoType = SchemaInfo::IMPORT;
|
|
restoreSchemaInfo(impInfo, infoType);
|
|
}
|
|
}
|
|
else {
|
|
|
|
attGroupInfo = fAttGroupRegistry->get(localPart);
|
|
}
|
|
|
|
if (!attGroupInfo) {
|
|
|
|
// traverse top level attributeGroup - if found
|
|
DOMElement* attGroupElem = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_AttributeGroup,
|
|
SchemaSymbols::fgELT_ATTRIBUTEGROUP, localPart, &fSchemaInfo);
|
|
|
|
if (attGroupElem != 0) {
|
|
|
|
// circular attribute check
|
|
if (fDeclStack->containsElement(attGroupElem)) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoCircularDefinition, refName);
|
|
return 0;
|
|
}
|
|
|
|
attGroupInfo = traverseAttributeGroupDecl(attGroupElem, typeInfo, true);
|
|
|
|
if (attGroupInfo && fCurrentAttGroupInfo) {
|
|
copyAttGroupAttributes(elem, attGroupInfo, fCurrentAttGroupInfo, 0);
|
|
}
|
|
|
|
// restore schema information, if necessary
|
|
if (saveInfo != fSchemaInfo) {
|
|
restoreSchemaInfo(saveInfo, infoType, saveScope);
|
|
}
|
|
|
|
return attGroupInfo;
|
|
}
|
|
else {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNotFound,
|
|
SchemaSymbols::fgELT_ATTRIBUTEGROUP, uriStr, localPart);
|
|
}
|
|
}
|
|
|
|
if (attGroupInfo) {
|
|
copyAttGroupAttributes(elem, attGroupInfo, fCurrentAttGroupInfo, typeInfo);
|
|
}
|
|
|
|
// restore schema information, if necessary
|
|
if (saveInfo != fSchemaInfo) {
|
|
restoreSchemaInfo(saveInfo, infoType);
|
|
}
|
|
|
|
return attGroupInfo;
|
|
}
|
|
|
|
void TraverseSchema::processElements(const DOMElement* const elem,
|
|
ComplexTypeInfo* const baseTypeInfo,
|
|
ComplexTypeInfo* const newTypeInfo) {
|
|
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
XMLSize_t elemCount = baseTypeInfo->elementCount();
|
|
|
|
if (elemCount) {
|
|
|
|
int newTypeScope = newTypeInfo->getScopeDefined();
|
|
int schemaURI = fURIStringPool->addOrFind(SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
|
|
|
|
for (XMLSize_t i=0; i < elemCount; i++) {
|
|
|
|
SchemaGrammar* aGrammar = fSchemaGrammar;
|
|
SchemaElementDecl* elemDecl = baseTypeInfo->elementAt(i);
|
|
int elemURI = elemDecl->getURI();
|
|
unsigned int elemScope = elemDecl->getEnclosingScope();
|
|
|
|
if (elemScope != Grammar::TOP_LEVEL_SCOPE) {
|
|
|
|
if (elemURI != fTargetNSURI && elemURI != schemaURI && elemURI != fEmptyNamespaceURI) {
|
|
Grammar* aGrammar = fGrammarResolver->getGrammar(fURIStringPool->getValueForId(elemURI));
|
|
|
|
if (!aGrammar || aGrammar->getGrammarType() != Grammar::SchemaGrammarType) {
|
|
continue; // REVISIT - error message
|
|
}
|
|
}
|
|
|
|
const XMLCh* localPart = elemDecl->getBaseName();
|
|
const SchemaElementDecl* other = (SchemaElementDecl*)
|
|
aGrammar->getElemDecl(elemURI, localPart, 0, newTypeScope);
|
|
|
|
if (other) {
|
|
|
|
if (elemDecl->getComplexTypeInfo() != other->getComplexTypeInfo()
|
|
|| elemDecl->getDatatypeValidator() != other->getDatatypeValidator()) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateElementDeclaration, localPart);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
elemDecl->setEnclosingScope(newTypeScope);
|
|
((SchemaGrammar*) aGrammar)->putGroupElemDecl(elemDecl);
|
|
elemDecl->setEnclosingScope(elemScope);
|
|
}
|
|
|
|
newTypeInfo->addElement(elemDecl);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TraverseSchema::processElements(const DOMElement* const elem,
|
|
XercesGroupInfo* const fromGroup,
|
|
ComplexTypeInfo* const typeInfo)
|
|
{
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
XMLSize_t elemCount = fromGroup->elementCount();
|
|
int newScope = typeInfo->getScopeDefined();
|
|
|
|
for (XMLSize_t i = 0; i < elemCount; i++) {
|
|
|
|
SchemaElementDecl* elemDecl = fromGroup->elementAt(i);
|
|
unsigned int elemScope = elemDecl->getEnclosingScope();
|
|
|
|
if (elemScope != Grammar::TOP_LEVEL_SCOPE)
|
|
{
|
|
int elemURI = elemDecl->getURI();
|
|
const XMLCh* localPart = elemDecl->getBaseName();
|
|
const SchemaElementDecl* other = (SchemaElementDecl*)
|
|
fSchemaGrammar->getElemDecl(elemURI, localPart, 0, newScope);
|
|
|
|
if (other)
|
|
{
|
|
if (elemDecl->getComplexTypeInfo() != other->getComplexTypeInfo()
|
|
|| elemDecl->getDatatypeValidator() != other->getDatatypeValidator())
|
|
{
|
|
reportSchemaError(
|
|
elem, XMLUni::fgXMLErrDomain
|
|
, XMLErrs::DuplicateElementDeclaration, localPart);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
elemDecl->setEnclosingScope(newScope);
|
|
fSchemaGrammar->putGroupElemDecl(elemDecl);
|
|
elemDecl->setEnclosingScope(elemScope);
|
|
typeInfo->addElement(elemDecl);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void TraverseSchema::copyGroupElements(const DOMElement* const elem,
|
|
XercesGroupInfo* const fromGroup,
|
|
XercesGroupInfo* const toGroup,
|
|
ComplexTypeInfo* const typeInfo) {
|
|
|
|
XMLSize_t elemCount = fromGroup->elementCount();
|
|
int newScope = (typeInfo) ? typeInfo->getScopeDefined() : 0;
|
|
|
|
if (typeInfo)
|
|
fromGroup->setCheckElementConsistency(false);
|
|
|
|
for (XMLSize_t i = 0; i < elemCount; i++) {
|
|
|
|
SchemaElementDecl* elemDecl = fromGroup->elementAt(i);
|
|
|
|
if (typeInfo) {
|
|
|
|
unsigned int elemScope = elemDecl->getEnclosingScope();
|
|
|
|
if (elemScope != Grammar::TOP_LEVEL_SCOPE) {
|
|
|
|
int elemURI = elemDecl->getURI();
|
|
const XMLCh* localPart = elemDecl->getBaseName();
|
|
const SchemaElementDecl* other = (SchemaElementDecl*)
|
|
fSchemaGrammar->getElemDecl(elemURI, localPart, 0, newScope);
|
|
|
|
if (other) {
|
|
|
|
if (elemDecl->getComplexTypeInfo() != other->getComplexTypeInfo()
|
|
|| elemDecl->getDatatypeValidator() != other->getDatatypeValidator()) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateElementDeclaration, localPart);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
elemDecl->setEnclosingScope(newScope);
|
|
fSchemaGrammar->putGroupElemDecl(elemDecl);
|
|
elemDecl->setEnclosingScope(elemScope);
|
|
}
|
|
|
|
typeInfo->addElement(elemDecl);
|
|
}
|
|
|
|
if (toGroup) {
|
|
toGroup->addElement(elemDecl);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TraverseSchema::copyAttGroupAttributes(const DOMElement* const elem,
|
|
XercesAttGroupInfo* const fromAttGroup,
|
|
XercesAttGroupInfo* const toAttGroup,
|
|
ComplexTypeInfo* const typeInfo) {
|
|
|
|
XMLSize_t attCount = fromAttGroup->attributeCount();
|
|
|
|
for (XMLSize_t i=0; i < attCount; i++) {
|
|
|
|
SchemaAttDef* attDef = fromAttGroup->attributeAt(i);
|
|
QName* attName = attDef->getAttName();
|
|
const XMLCh* localPart = attName->getLocalPart();
|
|
DatatypeValidator* attDV = attDef->getDatatypeValidator();
|
|
|
|
if (typeInfo) {
|
|
|
|
if (typeInfo->getAttDef(localPart, attName->getURI())) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttribute, localPart);
|
|
continue;
|
|
}
|
|
|
|
if (attDV && attDV->getType() == DatatypeValidator::ID) {
|
|
|
|
if (typeInfo->containsAttWithTypeId()) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttDeclPropCorrect5, localPart);
|
|
continue;
|
|
}
|
|
|
|
typeInfo->setAttWithTypeId(true);
|
|
}
|
|
|
|
SchemaAttDef* clonedAttDef = new (fGrammarPoolMemoryManager) SchemaAttDef(attDef);
|
|
typeInfo->addAttDef(clonedAttDef);
|
|
|
|
if (!clonedAttDef->getBaseAttDecl())
|
|
clonedAttDef->setBaseAttDecl(attDef);
|
|
|
|
if (toAttGroup) {
|
|
toAttGroup->addAttDef(attDef, true);
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (toAttGroup->containsAttribute(localPart, attName->getURI())) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttribute, localPart);
|
|
continue;
|
|
}
|
|
|
|
if (attDV && attDV->getType() == DatatypeValidator::ID) {
|
|
|
|
if (toAttGroup->containsTypeWithId()) {
|
|
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttGrpPropCorrect3, localPart);
|
|
continue;
|
|
}
|
|
|
|
toAttGroup->setTypeWithId(true);
|
|
}
|
|
|
|
toAttGroup->addAttDef(attDef, true);
|
|
}
|
|
}
|
|
|
|
if (toAttGroup) {
|
|
XMLSize_t anyAttCount = fromAttGroup->anyAttributeCount();
|
|
|
|
for (XMLSize_t j=0; j < anyAttCount; j++) {
|
|
toAttGroup->addAnyAttDef(fromAttGroup->anyAttributeAt(j), true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
TraverseSchema::attWildCardIntersection(SchemaAttDef* const resultWildCard,
|
|
const SchemaAttDef* const compareWildCard) {
|
|
|
|
XMLAttDef::AttTypes typeR = resultWildCard->getType();
|
|
XMLAttDef::AttTypes typeC = compareWildCard->getType();
|
|
|
|
//If either O1 or O2 is any, then the other must be the value.
|
|
if (typeC == XMLAttDef::Any_Any ||
|
|
typeR == XMLAttDef::AttTypes_Unknown) {
|
|
return;
|
|
}
|
|
|
|
if (typeR == XMLAttDef::Any_Any ||
|
|
typeC == XMLAttDef::AttTypes_Unknown) {
|
|
|
|
resultWildCard->resetNamespaceList();
|
|
copyWildCardData(compareWildCard, resultWildCard);
|
|
return;
|
|
}
|
|
|
|
// If either O1 or O2 is a pair of not and a namespace name and the other
|
|
// is a set, then that set, minus the negated namespace name if it was in
|
|
// is the value
|
|
if ((typeC == XMLAttDef::Any_Other && typeR == XMLAttDef::Any_List) ||
|
|
(typeR == XMLAttDef::Any_Other && typeC == XMLAttDef::Any_List)) {
|
|
|
|
unsigned int compareURI = 0;
|
|
ValueVectorOf<unsigned int>* nameURIList = 0;
|
|
|
|
if (typeC == XMLAttDef::Any_List) {
|
|
nameURIList = compareWildCard->getNamespaceList();
|
|
compareURI = resultWildCard->getAttName()->getURI();
|
|
}
|
|
else {
|
|
nameURIList = resultWildCard->getNamespaceList();
|
|
compareURI = compareWildCard->getAttName()->getURI();
|
|
}
|
|
|
|
XMLSize_t listSize = (nameURIList) ? nameURIList->size() : 0;
|
|
|
|
if (listSize) {
|
|
|
|
bool found = false;
|
|
ValueVectorOf<unsigned int> tmpURIList(listSize, fGrammarPoolMemoryManager);
|
|
|
|
for (XMLSize_t i=0; i < listSize; i++) {
|
|
|
|
unsigned int nameURI = nameURIList->elementAt(i);
|
|
|
|
if (nameURI != compareURI &&
|
|
nameURI != (unsigned int) fEmptyNamespaceURI) {
|
|
tmpURIList.addElement(nameURI);
|
|
}
|
|
else {
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
if (found || typeC == XMLAttDef::Any_List) {
|
|
resultWildCard->setNamespaceList(&tmpURIList);
|
|
}
|
|
}
|
|
|
|
if (typeC == XMLAttDef::Any_List) {
|
|
copyWildCardData(compareWildCard, resultWildCard);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// If both O1 and O2 are sets, then the intersection of those sets must be
|
|
// the value.
|
|
if (typeR == XMLAttDef::Any_List && typeC == XMLAttDef::Any_List) {
|
|
|
|
ValueVectorOf<unsigned int>* uriListR = resultWildCard->getNamespaceList();
|
|
ValueVectorOf<unsigned int>* uriListC = compareWildCard->getNamespaceList();
|
|
XMLSize_t listSize = (uriListC) ? uriListC->size() : 0;
|
|
|
|
if (listSize) {
|
|
|
|
ValueVectorOf<unsigned int> tmpURIList(listSize, fGrammarPoolMemoryManager);
|
|
|
|
for (XMLSize_t i=0; i < listSize; i++) {
|
|
|
|
unsigned int uriName = uriListC->elementAt(i);
|
|
|
|
if (uriListR && uriListR->containsElement(uriName)) {
|
|
tmpURIList.addElement(uriName);
|
|
}
|
|
}
|
|
|
|
resultWildCard->setNamespaceList(&tmpURIList);
|
|
}
|
|
else {
|
|
resultWildCard->resetNamespaceList();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// If the two are negations of different namespace names, then:
|
|
// if one is a negation of absent, then result is negation of namespace
|
|
// else intersection is not expressible.
|
|
if (typeR == XMLAttDef::Any_Other && typeC == XMLAttDef::Any_Other) {
|
|
|
|
QName* qnameR = resultWildCard->getAttName();
|
|
|
|
if (qnameR->getURI() != compareWildCard->getAttName()->getURI()) {
|
|
|
|
if (qnameR->getURI() == (unsigned int)fEmptyNamespaceURI) {
|
|
qnameR->setURI(compareWildCard->getAttName()->getURI());
|
|
}
|
|
else if (compareWildCard->getAttName()->getURI() != (unsigned int)fEmptyNamespaceURI) {
|
|
|
|
qnameR->setURI(fEmptyNamespaceURI);
|
|
resultWildCard->setType(XMLAttDef::AttTypes_Unknown);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
TraverseSchema::attWildCardUnion(SchemaAttDef* const resultWildCard,
|
|
const SchemaAttDef* const compareWildCard) {
|
|
|
|
XMLAttDef::AttTypes typeR = resultWildCard->getType();
|
|
XMLAttDef::AttTypes typeC = compareWildCard->getType();
|
|
|
|
//If either O1 or O2 is any, then the other must be the value.
|
|
if (typeR == XMLAttDef::Any_Any ||
|
|
typeR == XMLAttDef::AttTypes_Unknown) {
|
|
return;
|
|
}
|
|
|
|
if (typeC == XMLAttDef::Any_Any ||
|
|
typeC == XMLAttDef::AttTypes_Unknown) {
|
|
|
|
resultWildCard->resetNamespaceList();
|
|
copyWildCardData(compareWildCard, resultWildCard);
|
|
return;
|
|
}
|
|
|
|
// If both O1 and O2 are sets, then the union of those sets must be
|
|
// the value.
|
|
if (typeR == XMLAttDef::Any_List && typeC == XMLAttDef::Any_List) {
|
|
|
|
ValueVectorOf<unsigned int>* uriListR = resultWildCard->getNamespaceList();
|
|
ValueVectorOf<unsigned int>* uriListC = compareWildCard->getNamespaceList();
|
|
XMLSize_t listSizeC = (uriListC) ? uriListC->size() : 0;
|
|
|
|
if (listSizeC) {
|
|
|
|
if (!uriListR || !uriListR->size()) {
|
|
|
|
resultWildCard->setNamespaceList(uriListC);
|
|
return;
|
|
}
|
|
|
|
ValueVectorOf<unsigned int> tmpURIList(*uriListR);
|
|
|
|
for (XMLSize_t i = 0; i < listSizeC; i++) {
|
|
|
|
unsigned int uriName = uriListC->elementAt(i);
|
|
|
|
if (!uriListR->containsElement(uriName)) {
|
|
tmpURIList.addElement(uriName);
|
|
}
|
|
}
|
|
|
|
resultWildCard->setNamespaceList(&tmpURIList);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// If the two are negations of different namespace names, then not and
|
|
// absent must be the value
|
|
if (typeR == XMLAttDef::Any_Other && typeC == XMLAttDef::Any_Other) {
|
|
|
|
QName* qnameR = resultWildCard->getAttName();
|
|
|
|
if (qnameR->getURI() != compareWildCard->getAttName()->getURI()) {
|
|
|
|
qnameR->setURI(fEmptyNamespaceURI);
|
|
resultWildCard->setType(XMLAttDef::Any_Other);
|
|
}
|
|
}
|
|
|
|
// 5. If either O1 or O2 is a pair of not and a namespace name and the
|
|
// other is a set, then:
|
|
// 1. If the set includes both the negated namespace name and absent
|
|
// then any must be the value.
|
|
// 2. If the set includes the negated namespace name but not absent,
|
|
// then a pair of not and absent must be the value.
|
|
// 3. If the set includes absent but not the negated namespace name,
|
|
// then the union is not expressible.
|
|
// 4. If the set does not include either the negated namespace or
|
|
// absent, then whichever of O1 or O2 is a pair of not and a
|
|
// namespace name.
|
|
//
|
|
// 6. If either O1 or O2 is a pair of not and absent and the other is a
|
|
// set, then:
|
|
// 1. If the set includes absent then any must be the value.
|
|
// 2. If the set does not include absent, then a pair of not and
|
|
// absent.
|
|
if ((typeC == XMLAttDef::Any_Other && typeR == XMLAttDef::Any_List) ||
|
|
(typeR == XMLAttDef::Any_Other && typeC == XMLAttDef::Any_List)) {
|
|
|
|
ValueVectorOf<unsigned int>* nameURIList = 0;
|
|
QName* attNameR = resultWildCard->getAttName();
|
|
unsigned int compareURI = 0;
|
|
|
|
if (typeC == XMLAttDef::Any_List) {
|
|
nameURIList = compareWildCard->getNamespaceList();
|
|
compareURI = attNameR->getURI();
|
|
}
|
|
else {
|
|
nameURIList = resultWildCard->getNamespaceList();
|
|
compareURI = compareWildCard->getAttName()->getURI();
|
|
}
|
|
|
|
// 6. not and absent
|
|
if (compareURI == (unsigned int) fEmptyNamespaceURI) {
|
|
|
|
if (nameURIList) {
|
|
|
|
// 6.1 result is any
|
|
if (nameURIList->containsElement(compareURI)) {
|
|
|
|
resultWildCard->setType(XMLAttDef::Any_Any);
|
|
attNameR->setURI(fEmptyNamespaceURI);
|
|
}
|
|
// 6.2 result is not and absent
|
|
else if (typeR == XMLAttDef::Any_List){
|
|
|
|
resultWildCard->setType(XMLAttDef::Any_Other);
|
|
attNameR->setURI(fEmptyNamespaceURI);
|
|
}
|
|
}
|
|
// 6.2 result is not and absent
|
|
else if (typeR == XMLAttDef::Any_List) {
|
|
|
|
resultWildCard->setType(XMLAttDef::Any_Other);
|
|
attNameR->setURI(fEmptyNamespaceURI);
|
|
}
|
|
}
|
|
// 5. not and namespace
|
|
else {
|
|
|
|
// 5.3 result is not expressible
|
|
if (!nameURIList) {
|
|
resultWildCard->setType(XMLAttDef::AttTypes_Unknown);
|
|
attNameR->setURI(fEmptyNamespaceURI);
|
|
}
|
|
else {
|
|
bool containsAbsent =
|
|
nameURIList->containsElement(fEmptyNamespaceURI);
|
|
bool containsNamespace =
|
|
nameURIList->containsElement(compareURI);
|
|
|
|
// 5.1 result is any
|
|
if (containsAbsent && containsNamespace) {
|
|
|
|
resultWildCard->setType(XMLAttDef::Any_Any);
|
|
attNameR->setURI(fEmptyNamespaceURI);
|
|
}
|
|
// 5.2 result is not and absent
|
|
else if (containsNamespace) {
|
|
|
|
resultWildCard->setType(XMLAttDef::Any_Other);
|
|
attNameR->setURI(fEmptyNamespaceURI);
|
|
}
|
|
// 5.3 result is not expressible
|
|
else if (containsAbsent) {
|
|
|
|
resultWildCard->setType(XMLAttDef::AttTypes_Unknown);
|
|
attNameR->setURI(fEmptyNamespaceURI);
|
|
}
|
|
// 5.4. whichever is not and namespace
|
|
else if (typeR == XMLAttDef::Any_List) {
|
|
|
|
resultWildCard->setType(XMLAttDef::Any_Other);
|
|
attNameR->setURI(compareURI);
|
|
}
|
|
}
|
|
}
|
|
|
|
resultWildCard->resetNamespaceList();
|
|
}
|
|
}
|
|
|
|
|
|
void TraverseSchema::checkAttDerivationOK(const DOMElement* const elem,
|
|
const ComplexTypeInfo* const baseTypeInfo,
|
|
const ComplexTypeInfo* const childTypeInfo) {
|
|
|
|
SchemaAttDefList& childAttList = (SchemaAttDefList&) childTypeInfo->getAttDefList();
|
|
const SchemaAttDef* baseAttWildCard = baseTypeInfo->getAttWildCard();
|
|
|
|
for (XMLSize_t i=0; i<childAttList.getAttDefCount(); i++) {
|
|
|
|
SchemaAttDef& childAttDef = (SchemaAttDef&) childAttList.getAttDef(i);
|
|
QName* childAttName = childAttDef.getAttName();
|
|
const XMLCh* childLocalPart = childAttName->getLocalPart();
|
|
const SchemaAttDef* baseAttDef = baseTypeInfo->getAttDef(childLocalPart, childAttName->getURI());
|
|
|
|
if (baseAttDef) {
|
|
|
|
XMLAttDef::DefAttTypes baseAttDefType = baseAttDef->getDefaultType();
|
|
XMLAttDef::DefAttTypes childAttDefType = childAttDef.getDefaultType();
|
|
|
|
// Constraint 2.1.1 & 3 + check for prohibited base attribute
|
|
if (baseAttDefType == XMLAttDef::Prohibited
|
|
&& childAttDefType != XMLAttDef::Prohibited) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_8, childLocalPart);
|
|
}
|
|
|
|
if ((baseAttDefType & XMLAttDef::Required)
|
|
&& !(childAttDefType & XMLAttDef::Required)) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_2, childLocalPart);
|
|
}
|
|
|
|
// if the attribute in the derived type is prohibited, and it didn't try to override a required attribute,
|
|
// it's ok and shouldn't be tested for data type or fixed value
|
|
if (childAttDefType == XMLAttDef::Prohibited)
|
|
continue;
|
|
|
|
// Constraint 2.1.2
|
|
DatatypeValidator* baseDV = baseAttDef->getDatatypeValidator();
|
|
DatatypeValidator* childDV = childAttDef.getDatatypeValidator();
|
|
if (!baseDV || !baseDV->isSubstitutableBy(childDV)) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_3, childLocalPart);
|
|
}
|
|
|
|
// Constraint 2.1.3
|
|
if ((baseAttDefType & XMLAttDef::Fixed) &&
|
|
(!(childAttDefType & XMLAttDef::Fixed) ||
|
|
!XMLString::equals(baseAttDef->getValue(), childAttDef.getValue()))) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_4, childLocalPart);
|
|
}
|
|
}
|
|
// Constraint 2.2
|
|
else if (!baseAttWildCard ||
|
|
!wildcardAllowsNamespace(baseAttWildCard, childAttName->getURI())) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_5, childLocalPart);
|
|
}
|
|
}
|
|
|
|
// Constraint 4
|
|
const SchemaAttDef* childAttWildCard = childTypeInfo->getAttWildCard();
|
|
|
|
if (childAttWildCard) {
|
|
|
|
if (!baseAttWildCard) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_6);
|
|
}
|
|
else if (!isWildCardSubset(baseAttWildCard, childAttWildCard)) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_7);
|
|
}
|
|
else if (childAttWildCard->getDefaultType() < baseAttWildCard->getDefaultType()) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_9);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TraverseSchema::checkAttDerivationOK(const DOMElement* const elem,
|
|
const XercesAttGroupInfo* const baseAttGrpInfo,
|
|
const XercesAttGroupInfo* const childAttGrpInfo) {
|
|
|
|
XMLSize_t baseAttCount = baseAttGrpInfo->attributeCount();
|
|
XMLSize_t baseAnyAttCount = baseAttGrpInfo->anyAttributeCount();
|
|
XMLSize_t childAttCount = childAttGrpInfo->attributeCount();
|
|
XMLSize_t childAnyAttCount = childAttGrpInfo->anyAttributeCount();
|
|
|
|
if ((childAttCount || childAnyAttCount) && (!baseAttCount && !baseAnyAttCount)) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_1);
|
|
}
|
|
|
|
const SchemaAttDef* baseAttWildCard = (baseAnyAttCount) ? baseAttGrpInfo->anyAttributeAt(0) : 0;
|
|
|
|
for (XMLSize_t i=0; i<childAttCount; i++) {
|
|
|
|
const SchemaAttDef* childAttDef = childAttGrpInfo->attributeAt(i);
|
|
QName* childAttName = childAttDef->getAttName();
|
|
const XMLCh* childLocalPart = childAttName->getLocalPart();
|
|
const SchemaAttDef* baseAttDef = baseAttGrpInfo->getAttDef(childLocalPart, childAttName->getURI());
|
|
|
|
if (baseAttDef) {
|
|
|
|
XMLAttDef::DefAttTypes baseAttDefType = baseAttDef->getDefaultType();
|
|
XMLAttDef::DefAttTypes childAttDefType = childAttDef->getDefaultType();
|
|
|
|
// Constraint 2.1.1 & 3 + check for prohibited base attribute
|
|
if (baseAttDefType == XMLAttDef::Prohibited
|
|
&& childAttDefType != XMLAttDef::Prohibited) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_8, childLocalPart);
|
|
}
|
|
|
|
if ((baseAttDefType & XMLAttDef::Required)
|
|
&& !(childAttDefType & XMLAttDef::Required)) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_2, childLocalPart);
|
|
}
|
|
|
|
// if the attribute in the derived type is prohibited, and it didn't try to override a required attribute,
|
|
// it's ok and shouldn't be tested for data type or fixed value
|
|
if (childAttDefType == XMLAttDef::Prohibited)
|
|
continue;
|
|
|
|
// Constraint 2.1.2
|
|
DatatypeValidator* baseDV = baseAttDef->getDatatypeValidator();
|
|
DatatypeValidator* childDV = childAttDef->getDatatypeValidator();
|
|
if (!baseDV || !baseDV->isSubstitutableBy(childDV)) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_3, childLocalPart);
|
|
}
|
|
|
|
// Constraint 2.1.3
|
|
if ((baseAttDefType & XMLAttDef::Fixed) &&
|
|
(!(childAttDefType & XMLAttDef::Fixed) ||
|
|
!XMLString::equals(baseAttDef->getValue(), childAttDef->getValue()))) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_4, childLocalPart);
|
|
}
|
|
}
|
|
// Constraint 2.2
|
|
else if (!baseAttWildCard ||
|
|
!wildcardAllowsNamespace(baseAttWildCard, childAttName->getURI())) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_5, childLocalPart);
|
|
}
|
|
}
|
|
|
|
// Constraint 4
|
|
const SchemaAttDef* childAttWildCard = (childAnyAttCount) ? childAttGrpInfo->anyAttributeAt(0) : 0;
|
|
|
|
if (childAttWildCard) {
|
|
|
|
if (!baseAttWildCard) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_6);
|
|
}
|
|
else if (!isWildCardSubset(baseAttWildCard, childAttWildCard)) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_7);
|
|
}
|
|
else if (childAttWildCard->getDefaultType() < baseAttWildCard->getDefaultType()) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_9);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool TraverseSchema::wildcardAllowsNamespace(const SchemaAttDef* const wildCard,
|
|
const unsigned int nameURI) {
|
|
|
|
XMLAttDef::AttTypes wildCardType = wildCard->getType();
|
|
|
|
// The constraint must be any
|
|
if (wildCardType == XMLAttDef::Any_Any) {
|
|
return true;
|
|
}
|
|
|
|
// All of the following must be true:
|
|
// 2.1 The constraint is a pair of not and a namespace name or �absent
|
|
// 2.2 The value must not be identical to the �namespace test�.
|
|
// 2.3 The value must not be �absent�.
|
|
if (wildCardType == XMLAttDef::Any_Other &&
|
|
((int) nameURI) != fEmptyNamespaceURI &&
|
|
wildCard->getAttName()->getURI() != nameURI) {
|
|
return true;
|
|
}
|
|
|
|
// The constraint is a set, and the value is identical to one of the
|
|
// members of the set
|
|
if (wildCardType == XMLAttDef::Any_List) {
|
|
|
|
ValueVectorOf<unsigned int>* nameURIList = wildCard->getNamespaceList();
|
|
|
|
if (nameURIList->containsElement(nameURI)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool TraverseSchema::isWildCardSubset(const SchemaAttDef* const baseAttWildCard,
|
|
const SchemaAttDef* const childAttWildCard) {
|
|
|
|
XMLAttDef::AttTypes baseWildCardType = baseAttWildCard->getType();
|
|
XMLAttDef::AttTypes childWildCardType = childAttWildCard->getType();
|
|
|
|
if (baseWildCardType == XMLAttDef::AttTypes_Unknown ||
|
|
childWildCardType == XMLAttDef::AttTypes_Unknown) {
|
|
return false;
|
|
}
|
|
|
|
// 1 super must be any.
|
|
if (baseWildCardType == XMLAttDef::Any_Any) {
|
|
return true;
|
|
}
|
|
|
|
// 2 All of the following must be true:
|
|
// 2.1 sub must be a pair of not and a namespace name or �absent�.
|
|
// 2.2 super must be a pair of not and the same value.
|
|
if (childWildCardType == XMLAttDef::Any_Other && baseWildCardType == XMLAttDef::Any_Other &&
|
|
childAttWildCard->getAttName()->getURI() == baseAttWildCard->getAttName()->getURI()) {
|
|
return true;
|
|
}
|
|
|
|
// 3 All of the following must be true:
|
|
// 3.1 sub must be a set whose members are either namespace names or �absent�.
|
|
// 3.2 One of the following must be true:
|
|
// 3.2.1 super must be the same set or a superset thereof.
|
|
// 3.2.2 super must be a pair of not and a namespace name or �absent� and
|
|
// that value must not be in sub's set.
|
|
if (childWildCardType == XMLAttDef::Any_List) {
|
|
|
|
ValueVectorOf<unsigned int>* childURIList = childAttWildCard->getNamespaceList();
|
|
|
|
if (baseWildCardType == XMLAttDef::Any_List) {
|
|
|
|
ValueVectorOf<unsigned int>* baseURIList = baseAttWildCard->getNamespaceList();
|
|
XMLSize_t childListSize = (childURIList) ? childURIList->size() : 0;
|
|
|
|
for (XMLSize_t i=0; i<childListSize; i++) {
|
|
if (!baseURIList->containsElement(childURIList->elementAt(i))) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else if (baseWildCardType == XMLAttDef::Any_Other) {
|
|
if (!childURIList->containsElement(baseAttWildCard->getAttName()->getURI())) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool TraverseSchema::openRedefinedSchema(const DOMElement* const redefineElem) {
|
|
|
|
if (fPreprocessedNodes->containsKey(redefineElem)) {
|
|
|
|
restoreSchemaInfo(fPreprocessedNodes->get(redefineElem));
|
|
return true;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Get 'schemaLocation' attribute
|
|
// ------------------------------------------------------------------
|
|
const XMLCh* schemaLocation = getElementAttValue(redefineElem, SchemaSymbols::fgATT_SCHEMALOCATION, DatatypeValidator::AnyURI);
|
|
|
|
if (!schemaLocation || !*schemaLocation) {
|
|
reportSchemaError(redefineElem, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNoSchemaLocation, SchemaSymbols::fgELT_REDEFINE);
|
|
return false;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Resolve schema location
|
|
// ------------------------------------------------------------------
|
|
fLocator->setValues(fSchemaInfo->getCurrentSchemaURL(), 0,
|
|
((XSDElementNSImpl*) redefineElem)->getLineNo(),
|
|
((XSDElementNSImpl*) redefineElem)->getColumnNo());
|
|
InputSource* srcToFill = resolveSchemaLocation(schemaLocation,
|
|
XMLResourceIdentifier::SchemaRedefine);
|
|
Janitor<InputSource> janSrc(srcToFill);
|
|
|
|
// Nothing to do
|
|
if (!srcToFill) {
|
|
return false;
|
|
}
|
|
|
|
const XMLCh* includeURL = srcToFill->getSystemId();
|
|
|
|
if (XMLString::equals(includeURL, fSchemaInfo->getCurrentSchemaURL())) {
|
|
return false;
|
|
}
|
|
|
|
SchemaInfo* redefSchemaInfo = fCachedSchemaInfoList->get(includeURL, fTargetNSURI);
|
|
|
|
if (!redefSchemaInfo && fSchemaInfoList != fCachedSchemaInfoList)
|
|
redefSchemaInfo = fSchemaInfoList->get(includeURL, fTargetNSURI);
|
|
|
|
if (redefSchemaInfo) {
|
|
|
|
reportSchemaError(redefineElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidRedefine, includeURL);
|
|
return false;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Parse input source
|
|
// ------------------------------------------------------------------
|
|
if (!fParser)
|
|
fParser = new (fGrammarPoolMemoryManager) XSDDOMParser(0,fGrammarPoolMemoryManager, 0);
|
|
|
|
fParser->setValidationScheme(XercesDOMParser::Val_Never);
|
|
fParser->setDoNamespaces(true);
|
|
fParser->setUserEntityHandler(fEntityHandler);
|
|
fParser->setUserErrorReporter(fErrorReporter);
|
|
|
|
// Should just issue warning if the schema is not found
|
|
bool flag = srcToFill->getIssueFatalErrorIfNotFound();
|
|
srcToFill->setIssueFatalErrorIfNotFound(false);
|
|
|
|
fParser->parse(*srcToFill) ;
|
|
|
|
// Reset the InputSource
|
|
srcToFill->setIssueFatalErrorIfNotFound(flag);
|
|
|
|
if (fParser->getSawFatal() && fScanner->getExitOnFirstFatal())
|
|
reportSchemaError(redefineElem, XMLUni::fgXMLErrDomain, XMLErrs::SchemaScanFatalError);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Get root element
|
|
// ------------------------------------------------------------------
|
|
DOMDocument* document = fParser->getDocument();
|
|
|
|
if (!document) {
|
|
return false;
|
|
}
|
|
else {
|
|
|
|
DOMElement* root = document->getDocumentElement();
|
|
|
|
if (root == 0) {
|
|
return false;
|
|
}
|
|
|
|
const XMLCh* targetNSURIString = root->getAttribute(SchemaSymbols::fgATT_TARGETNAMESPACE);
|
|
|
|
// check to see if targetNameSpace is right
|
|
if (*targetNSURIString
|
|
&& !XMLString::equals(targetNSURIString,fTargetNSURIString)){
|
|
reportSchemaError(root, XMLUni::fgXMLErrDomain, XMLErrs::RedefineNamespaceDifference,
|
|
schemaLocation, targetNSURIString);
|
|
return false;
|
|
}
|
|
|
|
// if targetNamespace is empty, change it to redefin'g schema
|
|
// targetNamespace
|
|
if (!*targetNSURIString && root->getAttributeNode(XMLUni::fgXMLNSString) == 0
|
|
&& fTargetNSURI != fEmptyNamespaceURI) {
|
|
root->setAttribute(XMLUni::fgXMLNSString, fTargetNSURIString);
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Update schema information with redefined schema
|
|
// --------------------------------------------------------
|
|
redefSchemaInfo = fSchemaInfo;
|
|
Janitor<SchemaInfo> newSchemaInfo(new (fMemoryManager) SchemaInfo(0, 0, 0, fTargetNSURI,
|
|
0,
|
|
includeURL,
|
|
fTargetNSURIString, root,
|
|
fScanner,
|
|
fGrammarPoolMemoryManager));
|
|
fSchemaInfo = newSchemaInfo.get();
|
|
|
|
fSchemaInfo->getNamespaceScope()->reset(fEmptyNamespaceURI);
|
|
// Add mapping for the xml prefix
|
|
fSchemaInfo->getNamespaceScope()->addPrefix(XMLUni::fgXMLString, fURIStringPool->addOrFind(XMLUni::fgXMLURIName));
|
|
|
|
traverseSchemaHeader(root);
|
|
fSchemaInfoList->put((void*) fSchemaInfo->getCurrentSchemaURL(), fSchemaInfo->getTargetNSURI(), fSchemaInfo);
|
|
newSchemaInfo.release();
|
|
redefSchemaInfo->addSchemaInfo(fSchemaInfo, SchemaInfo::INCLUDE);
|
|
fPreprocessedNodes->put((void*) redefineElem, fSchemaInfo);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void TraverseSchema::renameRedefinedComponents(const DOMElement* const redefineElem,
|
|
SchemaInfo* const redefiningSchemaInfo,
|
|
SchemaInfo* const redefinedSchemaInfo) {
|
|
|
|
DOMElement* child = XUtil::getFirstChildElement(redefineElem);
|
|
|
|
for (; child != 0; child = XUtil::getNextSiblingElement(child)) {
|
|
|
|
const XMLCh* childName = child->getLocalName();
|
|
|
|
if (XMLString::equals(childName, SchemaSymbols::fgELT_ANNOTATION)) {
|
|
continue;
|
|
}
|
|
|
|
// if component already redefined skip
|
|
const XMLCh* typeName = getElementAttValue(child, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
|
|
fBuffer.set(fTargetNSURIString);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(typeName);
|
|
|
|
if (fRedefineComponents->containsKey(childName, fStringPool->addOrFind(fBuffer.getRawBuffer()))) {
|
|
continue;
|
|
}
|
|
|
|
// Rename
|
|
const XMLCh* tmpChildName = fStringPool->getValueForId(fStringPool->addOrFind(childName));
|
|
|
|
if (validateRedefineNameChange(child, tmpChildName, typeName, 1, redefiningSchemaInfo)) {
|
|
fixRedefinedSchema(child, redefinedSchemaInfo, tmpChildName, typeName, 1);
|
|
}
|
|
else {
|
|
redefiningSchemaInfo->addFailedRedefine(child);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool TraverseSchema::validateRedefineNameChange(const DOMElement* const redefineChildElem,
|
|
const XMLCh* const redefineChildComponentName,
|
|
const XMLCh* const redefineChildTypeName,
|
|
const int redefineNameCounter,
|
|
SchemaInfo* const redefiningSchemaInfo) {
|
|
|
|
const XMLCh* baseTypeName = 0;
|
|
unsigned int typeNameId = fStringPool->addOrFind(redefineChildTypeName);
|
|
|
|
fBuffer.set(fTargetNSURIString);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(redefineChildTypeName);
|
|
|
|
int fullTypeNameId = fStringPool->addOrFind(fBuffer.getRawBuffer());
|
|
const XMLCh* typeNameStr = fStringPool->getValueForId(fullTypeNameId);
|
|
|
|
restoreSchemaInfo(redefiningSchemaInfo);
|
|
|
|
if (XMLString::equals(redefineChildComponentName,SchemaSymbols::fgELT_SIMPLETYPE)) {
|
|
|
|
if (fDatatypeRegistry->getDatatypeValidator(typeNameStr)) {
|
|
return false;
|
|
}
|
|
|
|
DOMElement* grandKid = XUtil::getFirstChildElement(redefineChildElem);
|
|
|
|
if (grandKid && XMLString::equals(grandKid->getLocalName(), SchemaSymbols::fgELT_ANNOTATION)) {
|
|
grandKid = XUtil::getNextSiblingElement(grandKid);
|
|
}
|
|
|
|
if (grandKid == 0) {
|
|
|
|
reportSchemaError(redefineChildElem, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidSimpleType);
|
|
return false;
|
|
}
|
|
else if(!XMLString::equals(grandKid->getLocalName(), SchemaSymbols::fgELT_RESTRICTION)) {
|
|
|
|
reportSchemaError(grandKid, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidSimpleType);
|
|
return false;
|
|
}
|
|
|
|
baseTypeName = getElementAttValue(grandKid, SchemaSymbols::fgATT_BASE, DatatypeValidator::QName);
|
|
const XMLCh* prefix = getPrefix(baseTypeName);
|
|
const XMLCh* localPart = getLocalPart(baseTypeName);
|
|
const XMLCh* uriStr = resolvePrefixToURI(grandKid, prefix);
|
|
|
|
if (fTargetNSURI != (int) fURIStringPool->addOrFind(uriStr)
|
|
|| fStringPool->addOrFind(localPart) != typeNameId) {
|
|
reportSchemaError(grandKid, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidSimpleTypeBase);
|
|
return false;
|
|
}
|
|
|
|
// now we have to do the renaming...
|
|
getRedefineNewTypeName(baseTypeName, redefineNameCounter, fBuffer);
|
|
grandKid->setAttribute(SchemaSymbols::fgATT_BASE, fBuffer.getRawBuffer());
|
|
fRedefineComponents->put((void*) SchemaSymbols::fgELT_SIMPLETYPE,
|
|
fullTypeNameId, 0);
|
|
}
|
|
else if (XMLString::equals(redefineChildComponentName,SchemaSymbols::fgELT_COMPLEXTYPE)) {
|
|
|
|
if (fComplexTypeRegistry->containsKey(typeNameStr)) {
|
|
return false;
|
|
}
|
|
|
|
DOMElement* grandKid = XUtil::getFirstChildElement(redefineChildElem);
|
|
|
|
if (grandKid && XMLString::equals(grandKid->getLocalName(), SchemaSymbols::fgELT_ANNOTATION)) {
|
|
grandKid = XUtil::getNextSiblingElement(grandKid);
|
|
}
|
|
|
|
if (grandKid == 0) {
|
|
reportSchemaError(redefineChildElem, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidComplexType);
|
|
return false;
|
|
} else {
|
|
|
|
// have to go one more level down; let another pass worry whether complexType is valid.
|
|
DOMElement* greatGrandKid = XUtil::getFirstChildElement(grandKid);
|
|
|
|
if (greatGrandKid != 0 &&
|
|
XMLString::equals(greatGrandKid->getLocalName(), SchemaSymbols::fgELT_ANNOTATION)) {
|
|
greatGrandKid = XUtil::getNextSiblingElement(greatGrandKid);
|
|
}
|
|
|
|
if (greatGrandKid == 0) {
|
|
|
|
reportSchemaError(grandKid, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidComplexType);
|
|
return false;
|
|
} else {
|
|
|
|
const XMLCh* greatGrandKidName = greatGrandKid->getLocalName();
|
|
|
|
if (!XMLString::equals(greatGrandKidName, SchemaSymbols::fgELT_RESTRICTION)
|
|
&& !XMLString::equals(greatGrandKidName, SchemaSymbols::fgELT_EXTENSION)) {
|
|
|
|
reportSchemaError(greatGrandKid, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidComplexType);
|
|
return false;
|
|
}
|
|
|
|
baseTypeName = getElementAttValue(greatGrandKid, SchemaSymbols::fgATT_BASE, DatatypeValidator::QName);
|
|
const XMLCh* prefix = getPrefix(baseTypeName);
|
|
const XMLCh* localPart = getLocalPart(baseTypeName);
|
|
const XMLCh* uriStr = resolvePrefixToURI(greatGrandKid, prefix);
|
|
|
|
if (fTargetNSURI != (int) fURIStringPool->addOrFind(uriStr)
|
|
|| fStringPool->addOrFind(localPart) != typeNameId) {
|
|
reportSchemaError(greatGrandKid, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidComplexTypeBase);
|
|
return false;
|
|
}
|
|
|
|
// now we have to do the renaming...
|
|
getRedefineNewTypeName(baseTypeName, redefineNameCounter, fBuffer);
|
|
greatGrandKid->setAttribute(SchemaSymbols::fgATT_BASE, fBuffer.getRawBuffer());
|
|
fRedefineComponents->put((void*) SchemaSymbols::fgELT_COMPLEXTYPE,
|
|
fullTypeNameId, 0);
|
|
}
|
|
}
|
|
}
|
|
else if (XMLString::equals(redefineChildComponentName, SchemaSymbols::fgELT_GROUP)) {
|
|
|
|
if (fGroupRegistry->containsKey(typeNameStr)) {
|
|
return false;
|
|
}
|
|
|
|
int groupRefCount = changeRedefineGroup(redefineChildElem, redefineChildComponentName,
|
|
redefineChildTypeName, redefineNameCounter);
|
|
|
|
if (groupRefCount > 1) {
|
|
|
|
reportSchemaError(redefineChildElem, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_GroupRefCount);
|
|
return false;
|
|
}
|
|
else if (groupRefCount == 0) {
|
|
// put a dummy value, default is null.
|
|
// when processing groups, we will check that table, if a value
|
|
// is found, we need to do a particle derivation check.
|
|
fRedefineComponents->put((void*) SchemaSymbols::fgELT_GROUP,
|
|
fullTypeNameId, fSchemaInfo->getCurrentSchemaURL());
|
|
}
|
|
else {
|
|
fRedefineComponents->put((void*) SchemaSymbols::fgELT_GROUP, fullTypeNameId, 0);
|
|
}
|
|
}
|
|
else if (XMLString::equals(redefineChildComponentName, SchemaSymbols::fgELT_ATTRIBUTEGROUP)) {
|
|
|
|
if (fAttGroupRegistry->containsKey(redefineChildTypeName)) {
|
|
return false;
|
|
}
|
|
|
|
int attGroupRefCount = changeRedefineGroup(redefineChildElem, redefineChildComponentName,
|
|
redefineChildTypeName, redefineNameCounter);
|
|
|
|
if (attGroupRefCount > 1) {
|
|
|
|
reportSchemaError(redefineChildElem, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_AttGroupRefCount);
|
|
return false;
|
|
}
|
|
else if (attGroupRefCount == 0) {
|
|
// put a dummy value, default is null.
|
|
// when processing attributeGroups, we will check that table, if
|
|
// a value is found, we need to check for attribute derivation ok
|
|
// (by restriction)
|
|
fRedefineComponents->put((void*) SchemaSymbols::fgELT_ATTRIBUTEGROUP,
|
|
fullTypeNameId, fSchemaInfo->getCurrentSchemaURL());
|
|
}
|
|
else {
|
|
fRedefineComponents->put((void*) SchemaSymbols::fgELT_ATTRIBUTEGROUP, fullTypeNameId, 0);
|
|
}
|
|
}
|
|
else {
|
|
reportSchemaError
|
|
(
|
|
redefineChildElem
|
|
, XMLUni::fgXMLErrDomain
|
|
, XMLErrs::Redefine_InvalidChild
|
|
, redefineChildComponentName
|
|
);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int TraverseSchema::changeRedefineGroup(const DOMElement* const redefineChildElem,
|
|
const XMLCh* const redefineChildComponentName,
|
|
const XMLCh* const redefineChildTypeName,
|
|
const int redefineNameCounter) {
|
|
int result = 0;
|
|
DOMElement* child = XUtil::getFirstChildElement(redefineChildElem);
|
|
|
|
for (; child != 0; child = XUtil::getNextSiblingElement(child)) {
|
|
|
|
const XMLCh* name = child->getLocalName();
|
|
|
|
if (XMLString::equals(name, SchemaSymbols::fgELT_ANNOTATION)) {
|
|
continue;
|
|
}
|
|
|
|
if (!XMLString::equals(name, redefineChildComponentName)) {
|
|
result += changeRedefineGroup(child, redefineChildComponentName, redefineChildTypeName, redefineNameCounter);
|
|
} else {
|
|
const XMLCh* refName = getElementAttValue(child, SchemaSymbols::fgATT_REF, DatatypeValidator::QName);
|
|
|
|
if (refName && *refName) {
|
|
|
|
const XMLCh* prefix = getPrefix(refName);
|
|
const XMLCh* localPart = getLocalPart(refName);
|
|
const XMLCh* uriStr = resolvePrefixToURI(child, prefix);
|
|
|
|
if (fTargetNSURI == (int) fURIStringPool->addOrFind(uriStr)
|
|
&& fStringPool->addOrFind(localPart) == fStringPool->addOrFind(redefineChildTypeName)) {
|
|
|
|
// now we have to do the renaming...
|
|
getRedefineNewTypeName(refName, redefineNameCounter, fBuffer);
|
|
child->setAttribute(SchemaSymbols::fgATT_REF, fBuffer.getRawBuffer());
|
|
result++;
|
|
|
|
if(XMLString::equals(redefineChildComponentName, SchemaSymbols::fgELT_GROUP)) {
|
|
|
|
const XMLCh* minOccurs = getElementAttValue(child, SchemaSymbols::fgATT_MINOCCURS, DatatypeValidator::Decimal);
|
|
const XMLCh* maxOccurs = getElementAttValue(child, SchemaSymbols::fgATT_MAXOCCURS, DatatypeValidator::Decimal);
|
|
|
|
if (((maxOccurs && *maxOccurs) && !XMLString::equals(maxOccurs, fgValueOne))
|
|
|| ((minOccurs && *minOccurs) && !XMLString::equals(minOccurs, fgValueOne))) {
|
|
reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidGroupMinMax, redefineChildTypeName);
|
|
}
|
|
}
|
|
}
|
|
} // if ref was null some other stage of processing will flag the error
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
void TraverseSchema::fixRedefinedSchema(const DOMElement* const elem,
|
|
SchemaInfo* const redefinedSchemaInfo,
|
|
const XMLCh* const redefineChildComponentName,
|
|
const XMLCh* const redefineChildTypeName,
|
|
const int redefineNameCounter) {
|
|
|
|
bool foundIt = false;
|
|
DOMElement* child = XUtil::getFirstChildElement(redefinedSchemaInfo->getRoot());
|
|
|
|
restoreSchemaInfo(redefinedSchemaInfo);
|
|
|
|
for (; child != 0; child = XUtil::getNextSiblingElement(child)) {
|
|
|
|
const XMLCh* name = child->getLocalName();
|
|
|
|
if (XMLString::equals(name, redefineChildComponentName)) {
|
|
|
|
const XMLCh* infoItemName = getElementAttValue(child, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
|
|
if(!XMLString::equals(infoItemName, redefineChildTypeName)) {
|
|
continue;
|
|
}
|
|
else { // found it!
|
|
|
|
// now we have to do the renaming...
|
|
foundIt = true;
|
|
getRedefineNewTypeName(infoItemName, redefineNameCounter, fBuffer);
|
|
child->setAttribute(SchemaSymbols::fgATT_NAME, fBuffer.getRawBuffer());
|
|
break;
|
|
}
|
|
}
|
|
else if (XMLString::equals(name, SchemaSymbols::fgELT_REDEFINE)) { // need to search the redefine decl...
|
|
|
|
for (DOMElement* redefChild = XUtil::getFirstChildElement(child);
|
|
redefChild != 0;
|
|
redefChild = XUtil::getNextSiblingElement(redefChild)) {
|
|
|
|
const XMLCh* redefName = redefChild->getLocalName();
|
|
|
|
if (XMLString::equals(redefName, redefineChildComponentName)) {
|
|
|
|
const XMLCh* infoItemName = getElementAttValue(redefChild, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
|
|
|
|
if(!XMLString::equals(infoItemName, redefineChildTypeName)) {
|
|
continue;
|
|
}
|
|
else { // found it!
|
|
|
|
if (!openRedefinedSchema(child)) {
|
|
|
|
redefinedSchemaInfo->addFailedRedefine(child);
|
|
return;
|
|
}
|
|
|
|
foundIt = true;
|
|
|
|
SchemaInfo* reRedefinedSchemaInfo = fSchemaInfo;
|
|
|
|
if (validateRedefineNameChange(redefChild, redefineChildComponentName, redefineChildTypeName, redefineNameCounter + 1, redefinedSchemaInfo)) {
|
|
|
|
fixRedefinedSchema(redefChild, reRedefinedSchemaInfo, redefineChildComponentName, redefineChildTypeName, redefineNameCounter + 1);
|
|
|
|
// now we have to do the renaming...
|
|
getRedefineNewTypeName(infoItemName, redefineNameCounter, fBuffer);
|
|
const XMLCh* newInfoItemName = fStringPool->getValueForId(fStringPool->addOrFind(fBuffer.getRawBuffer()));
|
|
redefChild->setAttribute(SchemaSymbols::fgATT_NAME, newInfoItemName);
|
|
|
|
// and we now know we will traverse this, so set fRedefineComponents appropriately...
|
|
fBuffer.set(fTargetNSURIString);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(newInfoItemName);
|
|
}
|
|
else {
|
|
|
|
fixRedefinedSchema(redefChild, reRedefinedSchemaInfo, redefineChildComponentName, redefineChildTypeName, redefineNameCounter);
|
|
redefinedSchemaInfo->addFailedRedefine(redefChild);
|
|
|
|
// and we now know we will traverse this, so set fRedefineComponents appropriately...
|
|
fBuffer.set(fTargetNSURIString);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(infoItemName);
|
|
}
|
|
|
|
unsigned int infoItemNameId = fStringPool->addOrFind(fBuffer.getRawBuffer());
|
|
|
|
if (!fRedefineComponents->containsKey(redefineChildComponentName, infoItemNameId)) {
|
|
fRedefineComponents->put((void*) redefineChildComponentName, infoItemNameId, 0);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
} //for
|
|
|
|
if (foundIt) {
|
|
break;
|
|
}
|
|
}
|
|
} //for
|
|
|
|
if(!foundIt) {
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_DeclarationNotFound, redefineChildTypeName);
|
|
}
|
|
}
|
|
|
|
bool TraverseSchema::isSubstitutionGroupCircular(SchemaElementDecl* const elemDecl,
|
|
SchemaElementDecl* const subsElemDecl)
|
|
{
|
|
|
|
if (elemDecl == subsElemDecl)
|
|
return true;
|
|
|
|
SchemaElementDecl* tmpElemDecl = subsElemDecl->getSubstitutionGroupElem();
|
|
|
|
while (tmpElemDecl)
|
|
{
|
|
if (tmpElemDecl == elemDecl)
|
|
return true;
|
|
|
|
tmpElemDecl = tmpElemDecl->getSubstitutionGroupElem();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// TraverseSchema: Error reporting methods
|
|
// ---------------------------------------------------------------------------
|
|
void TraverseSchema::reportSchemaError(const XSDLocator* const aLocator,
|
|
const XMLCh* const msgDomain,
|
|
const int errorCode) {
|
|
|
|
fXSDErrorReporter.emitError(errorCode, msgDomain, aLocator);
|
|
}
|
|
|
|
void TraverseSchema::reportSchemaError(const XSDLocator* const aLocator,
|
|
const XMLCh* const msgDomain,
|
|
const int errorCode,
|
|
const XMLCh* const text1,
|
|
const XMLCh* const text2,
|
|
const XMLCh* const text3,
|
|
const XMLCh* const text4) {
|
|
|
|
fXSDErrorReporter.emitError(errorCode, msgDomain, aLocator, text1, text2, text3, text4, fMemoryManager);
|
|
}
|
|
|
|
void TraverseSchema::reportSchemaError(const DOMElement* const elem,
|
|
const XMLCh* const msgDomain,
|
|
const int errorCode) {
|
|
|
|
fLocator->setValues(fSchemaInfo->getCurrentSchemaURL(), 0,
|
|
((XSDElementNSImpl*) elem)->getLineNo(),
|
|
((XSDElementNSImpl*) elem)->getColumnNo());
|
|
|
|
fXSDErrorReporter.emitError(errorCode, msgDomain, fLocator);
|
|
}
|
|
|
|
void TraverseSchema::reportSchemaError(const DOMElement* const elem,
|
|
const XMLCh* const msgDomain,
|
|
const int errorCode,
|
|
const XMLCh* const text1,
|
|
const XMLCh* const text2,
|
|
const XMLCh* const text3,
|
|
const XMLCh* const text4) {
|
|
|
|
fLocator->setValues(fSchemaInfo->getCurrentSchemaURL(), 0,
|
|
((XSDElementNSImpl*) elem)->getLineNo(),
|
|
((XSDElementNSImpl*) elem)->getColumnNo());
|
|
|
|
fXSDErrorReporter.emitError(errorCode, msgDomain, fLocator, text1, text2, text3, text4, fMemoryManager);
|
|
}
|
|
|
|
void TraverseSchema::reportSchemaError(const DOMElement* const elem,
|
|
const XMLException& except)
|
|
{
|
|
fLocator->setValues(fSchemaInfo->getCurrentSchemaURL(), 0,
|
|
((XSDElementNSImpl*) elem)->getLineNo(),
|
|
((XSDElementNSImpl*) elem)->getColumnNo());
|
|
|
|
fXSDErrorReporter.emitError(except, fLocator);
|
|
}
|
|
// ---------------------------------------------------------------------------
|
|
// TraverseSchema: Init/CleanUp methods
|
|
// ---------------------------------------------------------------------------
|
|
void TraverseSchema::init() {
|
|
|
|
fXSDErrorReporter.setErrorReporter(fErrorReporter);
|
|
fXSDErrorReporter.setExitOnFirstFatal(fScanner->getExitOnFirstFatal());
|
|
|
|
fFullConstraintChecking = fScanner->getValidationSchemaFullChecking();
|
|
|
|
fDatatypeRegistry = fSchemaGrammar->getDatatypeRegistry();
|
|
fStringPool = fGrammarResolver->getStringPool();
|
|
fEmptyNamespaceURI = fScanner->getEmptyNamespaceId();
|
|
fCurrentTypeNameStack = new (fMemoryManager) ValueVectorOf<unsigned int>(8, fMemoryManager);
|
|
fCurrentGroupStack = new (fMemoryManager) ValueVectorOf<unsigned int>(8, fMemoryManager);
|
|
|
|
fGlobalDeclarations = (ValueVectorOf<unsigned int>**) fMemoryManager->allocate
|
|
(
|
|
ENUM_ELT_SIZE * sizeof(ValueVectorOf<unsigned int>*)
|
|
);//new ValueVectorOf<unsigned int>*[ENUM_ELT_SIZE];
|
|
memset(fGlobalDeclarations, 0, ENUM_ELT_SIZE * sizeof(ValueVectorOf<unsigned int>*));
|
|
for(unsigned int i=0; i < ENUM_ELT_SIZE; i++)
|
|
fGlobalDeclarations[i] = new (fMemoryManager) ValueVectorOf<unsigned int>(8, fMemoryManager);
|
|
|
|
fNonXSAttList = new (fMemoryManager) ValueVectorOf<DOMNode*>(4, fMemoryManager);
|
|
fNotationRegistry = new (fMemoryManager) RefHash2KeysTableOf<XMLCh>(13, (bool) false, fMemoryManager);
|
|
fPreprocessedNodes = new (fMemoryManager) RefHashTableOf<SchemaInfo, PtrHasher>
|
|
(
|
|
29
|
|
, false
|
|
, fMemoryManager
|
|
);
|
|
fLocator = new (fMemoryManager) XSDLocator();
|
|
fDeclStack = new (fMemoryManager) ValueVectorOf<const DOMElement*>(16, fMemoryManager);
|
|
}
|
|
|
|
void TraverseSchema::cleanUp() {
|
|
|
|
delete fCurrentTypeNameStack;
|
|
delete fCurrentGroupStack;
|
|
|
|
if (fGlobalDeclarations)
|
|
{
|
|
for(unsigned int i=0; i < ENUM_ELT_SIZE; i++)
|
|
delete fGlobalDeclarations[i];
|
|
fMemoryManager->deallocate(fGlobalDeclarations);//delete [] fGlobalDeclarations;
|
|
}
|
|
|
|
delete fNonXSAttList;
|
|
delete fImportedNSList;
|
|
delete fNotationRegistry;
|
|
delete fRedefineComponents;
|
|
delete fIdentityConstraintNames;
|
|
delete fDeclStack;
|
|
delete fIC_ElementsNS;
|
|
delete fIC_NodeListNS;
|
|
delete fPreprocessedNodes;
|
|
delete fLocator;
|
|
delete fParser;
|
|
}
|
|
|
|
void TraverseSchema::processElemDeclAttrs(const DOMElement* const elem,
|
|
SchemaElementDecl* const elemDecl,
|
|
const XMLCh*& valueConstraint,
|
|
bool isTopLevel)
|
|
{
|
|
int elementMiscFlags = 0;
|
|
const XMLCh* fixedVal = getElementAttValue(elem, SchemaSymbols::fgATT_FIXED);
|
|
const XMLCh* nillable = getElementAttValue(elem, SchemaSymbols::fgATT_NILLABLE, DatatypeValidator::Boolean);
|
|
|
|
// check constraint value
|
|
valueConstraint = getElementAttValue(elem, SchemaSymbols::fgATT_DEFAULT);
|
|
if (fixedVal)
|
|
{
|
|
elementMiscFlags |= SchemaSymbols::XSD_FIXED;
|
|
|
|
// if both default and fixed, emit an error
|
|
if (valueConstraint)
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::ElementWithFixedAndDefault, getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName));
|
|
|
|
// set constraint value to the fixed one
|
|
valueConstraint = fixedVal;
|
|
}
|
|
|
|
// check nillable
|
|
if (nillable && *nillable) {
|
|
|
|
if (XMLString::equals(nillable, SchemaSymbols::fgATTVAL_TRUE)
|
|
|| XMLString::equals(nillable, fgValueOne)) {
|
|
elementMiscFlags |= SchemaSymbols::XSD_NILLABLE;
|
|
}
|
|
}
|
|
|
|
if (isTopLevel)
|
|
{
|
|
const XMLCh* bAbstract = getElementAttValue(elem, SchemaSymbols::fgATT_ABSTRACT, DatatypeValidator::Boolean);
|
|
if (bAbstract && *bAbstract) {
|
|
|
|
if (XMLString::equals(bAbstract, SchemaSymbols::fgATTVAL_TRUE)
|
|
|| XMLString::equals(bAbstract, fgValueOne)) {
|
|
elementMiscFlags |= SchemaSymbols::XSD_ABSTRACT;
|
|
}
|
|
}
|
|
|
|
elemDecl->setFinalSet(parseFinalSet(elem, EC_Final));
|
|
}
|
|
|
|
elemDecl->setBlockSet(parseBlockSet(elem, ES_Block));
|
|
elemDecl->setMiscFlags(elementMiscFlags);
|
|
}
|
|
|
|
void TraverseSchema::processElemDeclIC(DOMElement* const icElem,
|
|
SchemaElementDecl* const elemDecl)
|
|
{
|
|
// key/keyref/unique processing
|
|
ValueVectorOf<DOMElement*>* icNodes = 0;
|
|
DOMElement* ic = icElem;
|
|
while (ic != 0) {
|
|
|
|
if (XMLString::equals(ic->getLocalName(), SchemaSymbols::fgELT_KEY)) {
|
|
traverseKey(ic, elemDecl);
|
|
}
|
|
else if (XMLString::equals(ic->getLocalName(), SchemaSymbols::fgELT_UNIQUE)) {
|
|
traverseUnique(ic, elemDecl);
|
|
}
|
|
else {
|
|
|
|
if (!icNodes) {
|
|
icNodes = new (fGrammarPoolMemoryManager) ValueVectorOf<DOMElement*>(8, fGrammarPoolMemoryManager);
|
|
}
|
|
|
|
icNodes->addElement(ic);
|
|
}
|
|
|
|
ic = XUtil::getNextSiblingElementNS(
|
|
ic, fgIdentityConstraints, SchemaSymbols::fgURI_SCHEMAFORSCHEMA, 3);
|
|
}
|
|
|
|
if (icNodes) {
|
|
|
|
if (!fIC_ElementsNS) {
|
|
|
|
fIC_ElementsNS = new (fMemoryManager) RefHashTableOf<ElemVector>(13, fMemoryManager);
|
|
fIC_NodeListNS = new (fMemoryManager) RefHashTableOf<ValueVectorOf<DOMElement*>, PtrHasher>(29, true, fMemoryManager);
|
|
}
|
|
|
|
fIC_Elements = fIC_ElementsNS->get(fTargetNSURIString);
|
|
if (!fIC_Elements) {
|
|
fIC_Elements = new (fMemoryManager) ValueVectorOf<SchemaElementDecl*>(8, fMemoryManager);
|
|
fIC_ElementsNS->put((void*) fTargetNSURIString, fIC_Elements);
|
|
}
|
|
|
|
fIC_NodeListNS->put(elemDecl, icNodes);
|
|
fIC_Elements->addElement(elemDecl);
|
|
}
|
|
}
|
|
|
|
bool
|
|
TraverseSchema::checkElemDeclValueConstraint(const DOMElement* const elem,
|
|
SchemaElementDecl* const elemDecl,
|
|
const XMLCh* const valConstraint,
|
|
ComplexTypeInfo* const typeInfo,
|
|
DatatypeValidator* const validator)
|
|
{
|
|
bool isValid = false;
|
|
if (validator)
|
|
{
|
|
if (validator->getType() == DatatypeValidator::ID)
|
|
reportSchemaError(
|
|
elem, XMLUni::fgXMLErrDomain, XMLErrs::ElemIDValueConstraint
|
|
, elemDecl->getBaseName(), valConstraint
|
|
);
|
|
|
|
try
|
|
{
|
|
const XMLCh* valueToCheck = valConstraint;
|
|
short wsFacet = validator->getWSFacet();
|
|
if((wsFacet == DatatypeValidator::REPLACE && !XMLString::isWSReplaced(valueToCheck)) ||
|
|
(wsFacet == DatatypeValidator::COLLAPSE && !XMLString::isWSCollapsed(valueToCheck)))
|
|
{
|
|
XMLCh* normalizedValue=XMLString::replicate(valueToCheck, fMemoryManager);
|
|
ArrayJanitor<XMLCh> tempURIName(normalizedValue, fMemoryManager);
|
|
if(wsFacet == DatatypeValidator::REPLACE)
|
|
XMLString::replaceWS(normalizedValue, fMemoryManager);
|
|
else if(wsFacet == DatatypeValidator::COLLAPSE)
|
|
XMLString::collapseWS(normalizedValue, fMemoryManager);
|
|
valueToCheck=fStringPool->getValueForId(fStringPool->addOrFind(normalizedValue));
|
|
}
|
|
|
|
validator->validate(valueToCheck,0,fMemoryManager);
|
|
|
|
XMLCh* canonical = (XMLCh*) validator->getCanonicalRepresentation(valueToCheck, fMemoryManager);
|
|
ArrayJanitor<XMLCh> tempCanonical(canonical, fMemoryManager);
|
|
|
|
if(!XMLString::equals(canonical, valueToCheck))
|
|
{
|
|
validator->validate(canonical, 0, fMemoryManager);
|
|
valueToCheck=fStringPool->getValueForId(fStringPool->addOrFind(canonical));
|
|
}
|
|
|
|
elemDecl->setDefaultValue(valueToCheck);
|
|
|
|
isValid = true;
|
|
}
|
|
catch(const XMLException& excep)
|
|
{
|
|
reportSchemaError(elem, excep);
|
|
}
|
|
catch(const OutOfMemoryException&)
|
|
{
|
|
throw;
|
|
}
|
|
catch(...)
|
|
{
|
|
reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::DatatypeValidationFailure, valConstraint);
|
|
}
|
|
}
|
|
|
|
if (typeInfo)
|
|
{
|
|
int contentSpecType = typeInfo->getContentType();
|
|
|
|
if (contentSpecType != SchemaElementDecl::Simple &&
|
|
contentSpecType != SchemaElementDecl::Mixed_Simple &&
|
|
contentSpecType != SchemaElementDecl::Mixed_Complex)
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NotSimpleOrMixedElement, elemDecl->getBaseName());
|
|
|
|
if (((contentSpecType == SchemaElementDecl::Mixed_Complex
|
|
|| contentSpecType == SchemaElementDecl::Mixed_Simple)
|
|
&& !emptiableParticle(typeInfo->getContentSpec())))
|
|
reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::EmptiableMixedContent, elemDecl->getBaseName());
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
void TraverseSchema::processSubstitutionGroup(const DOMElement* const elem,
|
|
SchemaElementDecl* const elemDecl,
|
|
ComplexTypeInfo*& typeInfo,
|
|
DatatypeValidator*& validator,
|
|
const XMLCh* const subsElemQName)
|
|
{
|
|
NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);
|
|
|
|
SchemaElementDecl* subsElemDecl = getGlobalElemDecl(elem, subsElemQName);
|
|
if (subsElemDecl)
|
|
{
|
|
if (isSubstitutionGroupCircular(elemDecl, subsElemDecl))
|
|
{
|
|
reportSchemaError(
|
|
elem , XMLUni::fgXMLErrDomain , XMLErrs::CircularSubsGroup, elemDecl->getBaseName());
|
|
}
|
|
else
|
|
{
|
|
// Check for substitution validity constraint
|
|
// Substitution allowed (block and blockDefault) && same type
|
|
if (isSubstitutionGroupValid(elem, subsElemDecl, typeInfo, validator, elemDecl->getBaseName()))
|
|
{
|
|
elemDecl->setSubstitutionGroupElem(subsElemDecl);
|
|
|
|
// if type information is missing, use subsGroup one
|
|
if (!typeInfo && !validator)
|
|
{
|
|
typeInfo = subsElemDecl->getComplexTypeInfo();
|
|
validator = subsElemDecl->getDatatypeValidator();
|
|
|
|
if (validator)
|
|
{
|
|
elemDecl->setDatatypeValidator(validator);
|
|
elemDecl->setModelType(SchemaElementDecl::Simple);
|
|
}
|
|
else if (typeInfo)
|
|
{
|
|
elemDecl->setComplexTypeInfo(typeInfo);
|
|
elemDecl->setModelType((SchemaElementDecl::ModelTypes)typeInfo->getContentType());
|
|
}
|
|
}
|
|
|
|
XMLCh* subsElemBaseName = subsElemDecl->getBaseName();
|
|
int subsElemURI = subsElemDecl->getURI();
|
|
ValueVectorOf<SchemaElementDecl*>* subsElements =
|
|
fValidSubstitutionGroups->get(subsElemBaseName, subsElemURI);
|
|
|
|
if (!subsElements && fTargetNSURI != subsElemURI)
|
|
{
|
|
SchemaGrammar* aGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(fURIStringPool->getValueForId(subsElemURI));
|
|
|
|
if (aGrammar)
|
|
{
|
|
subsElements = aGrammar->getValidSubstitutionGroups()->get(subsElemBaseName, subsElemURI);
|
|
|
|
if (subsElements)
|
|
{
|
|
subsElements = new (fGrammarPoolMemoryManager) ValueVectorOf<SchemaElementDecl*>(*subsElements);
|
|
fValidSubstitutionGroups->put(subsElemBaseName, subsElemURI, subsElements);
|
|
}
|
|
else if (fSchemaInfo->circularImportExist(subsElemURI))
|
|
{
|
|
aGrammar->getValidSubstitutionGroups()->put(
|
|
subsElemBaseName, subsElemURI, new (fGrammarPoolMemoryManager) ValueVectorOf<SchemaElementDecl*>(8, fGrammarPoolMemoryManager));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!subsElements)
|
|
{
|
|
subsElements = new (fGrammarPoolMemoryManager) ValueVectorOf<SchemaElementDecl*>(8, fGrammarPoolMemoryManager);
|
|
fValidSubstitutionGroups->put(subsElemBaseName, subsElemURI, subsElements);
|
|
}
|
|
|
|
subsElements->addElement(elemDecl);
|
|
|
|
// update related subs. info in case of circular import
|
|
BaseRefVectorEnumerator<SchemaInfo> importingEnum = fSchemaInfo->getImportingListEnumerator();
|
|
|
|
while (importingEnum.hasMoreElements())
|
|
{
|
|
const SchemaInfo& curRef = importingEnum.nextElement();
|
|
SchemaGrammar* aGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(curRef.getTargetNSURIString());
|
|
ValueVectorOf<SchemaElementDecl*>* subsElemList =
|
|
aGrammar->getValidSubstitutionGroups()->get(subsElemBaseName, subsElemURI);
|
|
|
|
if (subsElemList && !subsElemList->containsElement(elemDecl))
|
|
subsElemList->addElement(elemDecl);
|
|
}
|
|
|
|
buildValidSubstitutionListB(elem, elemDecl, subsElemDecl);
|
|
buildValidSubstitutionListF(elem, elemDecl, subsElemDecl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TraverseSchema::processAttValue(const XMLCh* const attVal,
|
|
XMLBuffer& aBuf)
|
|
{
|
|
// REVISIT-KN: assuming that attVal is not NULL
|
|
//
|
|
// normally, nothing will happen
|
|
const XMLCh* srcVal = attVal;
|
|
XMLCh nextCh = *srcVal;
|
|
while (nextCh)
|
|
{
|
|
if (nextCh <= chCloseAngle) {
|
|
switch (nextCh) {
|
|
case chDoubleQuote:
|
|
aBuf.append(chAmpersand);
|
|
aBuf.append(XMLUni::fgQuot);
|
|
aBuf.append(chSemiColon);
|
|
break;
|
|
case chSingleQuote:
|
|
aBuf.append(chAmpersand);
|
|
aBuf.append(XMLUni::fgApos);
|
|
aBuf.append(chSemiColon);
|
|
break;
|
|
case chCloseAngle:
|
|
aBuf.append(chAmpersand);
|
|
aBuf.append(XMLUni::fgGT);
|
|
aBuf.append(chSemiColon);
|
|
break;
|
|
case chOpenAngle:
|
|
aBuf.append(chAmpersand);
|
|
aBuf.append(XMLUni::fgLT);
|
|
aBuf.append(chSemiColon);
|
|
break;
|
|
case chAmpersand:
|
|
aBuf.append(chAmpersand);
|
|
aBuf.append(XMLUni::fgAmp);
|
|
aBuf.append(chSemiColon);
|
|
break;
|
|
default:
|
|
aBuf.append(nextCh);
|
|
break;
|
|
} // end switch
|
|
}
|
|
else
|
|
aBuf.append(nextCh);
|
|
|
|
nextCh = *++srcVal;
|
|
}
|
|
}
|
|
|
|
XSAnnotation* TraverseSchema::generateSyntheticAnnotation(const DOMElement* const elem
|
|
, ValueVectorOf<DOMNode*>* nonXSAttList)
|
|
{
|
|
const XMLCh* prefix = elem->getPrefix();
|
|
ValueHashTableOf<unsigned int>* listOfURIs = new (fMemoryManager) ValueHashTableOf<unsigned int>(29, fMemoryManager);
|
|
bool sawXMLNS = false;
|
|
|
|
fBuffer.reset();
|
|
fBuffer.append(chOpenAngle);
|
|
if (prefix)
|
|
{
|
|
fBuffer.append(prefix);
|
|
fBuffer.append(chColon);
|
|
}
|
|
fBuffer.append(SchemaSymbols::fgELT_ANNOTATION);
|
|
|
|
// next is the nonXSAttList names & values
|
|
XMLSize_t nonXSAttSize = nonXSAttList->size();
|
|
|
|
for (XMLSize_t i=0; i<nonXSAttSize; i++)
|
|
{
|
|
DOMNode* attNode = nonXSAttList->elementAt(i);
|
|
|
|
fBuffer.append(chSpace);
|
|
fBuffer.append(attNode->getNodeName());
|
|
fBuffer.append(chEqual);
|
|
fBuffer.append(chDoubleQuote);
|
|
processAttValue(attNode->getNodeValue(), fBuffer);
|
|
fBuffer.append(chDoubleQuote);
|
|
}
|
|
|
|
// next is the namespaces on the elem
|
|
DOMElement* currentElem = (DOMElement*) elem;
|
|
DOMNamedNodeMap* eltAttrs;
|
|
XMLSize_t attrCount;
|
|
do {
|
|
eltAttrs = currentElem->getAttributes();
|
|
attrCount = eltAttrs->getLength();
|
|
for (XMLSize_t j = 0; j < attrCount; j++)
|
|
{
|
|
DOMNode* attribute = eltAttrs->item(j);
|
|
const XMLCh* attName = attribute->getNodeName();
|
|
|
|
if (XMLString::startsWith(attName, XMLUni::fgXMLNSColonString))
|
|
{
|
|
if (!listOfURIs->containsKey((void*) attName)) {
|
|
listOfURIs->put((void*) attName, 0);
|
|
fBuffer.append(chSpace);
|
|
fBuffer.append(attName);
|
|
fBuffer.append(chEqual);
|
|
fBuffer.append(chDoubleQuote);
|
|
processAttValue(attribute->getNodeValue(), fBuffer);
|
|
fBuffer.append(chDoubleQuote);
|
|
}
|
|
}
|
|
else if (!sawXMLNS && XMLString::equals(attName, XMLUni::fgXMLNSString))
|
|
{
|
|
fBuffer.append(chSpace);
|
|
fBuffer.append(attName);
|
|
fBuffer.append(chEqual);
|
|
fBuffer.append(chDoubleQuote);
|
|
processAttValue(attribute->getNodeValue(), fBuffer);
|
|
fBuffer.append(chDoubleQuote);
|
|
sawXMLNS = true;
|
|
}
|
|
}
|
|
currentElem = (DOMElement*) currentElem->getParentNode();
|
|
}
|
|
while (currentElem != fSchemaInfo->getRoot()->getParentNode());
|
|
delete listOfURIs;
|
|
|
|
fBuffer.append(chCloseAngle);
|
|
fBuffer.append(chLF);
|
|
fBuffer.append(chOpenAngle);
|
|
if (prefix)
|
|
{
|
|
fBuffer.append(prefix);
|
|
fBuffer.append(chColon);
|
|
}
|
|
fBuffer.append(SchemaSymbols::fgELT_DOCUMENTATION);
|
|
fBuffer.append(chCloseAngle);
|
|
fBuffer.append(fgSynthetic_Annotation);
|
|
fBuffer.append(chOpenAngle);
|
|
fBuffer.append(chForwardSlash);
|
|
if (prefix)
|
|
{
|
|
fBuffer.append(prefix);
|
|
fBuffer.append(chColon);
|
|
}
|
|
fBuffer.append(SchemaSymbols::fgELT_DOCUMENTATION);
|
|
fBuffer.append(chCloseAngle);
|
|
fBuffer.append(chLF);
|
|
fBuffer.append(chOpenAngle);
|
|
fBuffer.append(chForwardSlash);
|
|
if (prefix)
|
|
{
|
|
fBuffer.append(prefix);
|
|
fBuffer.append(chColon);
|
|
}
|
|
fBuffer.append(SchemaSymbols::fgELT_ANNOTATION);
|
|
fBuffer.append(chCloseAngle);
|
|
|
|
XSAnnotation* annot = new (fGrammarPoolMemoryManager) XSAnnotation(fBuffer.getRawBuffer(), fGrammarPoolMemoryManager);
|
|
annot->setLineCol( ((XSDElementNSImpl*)elem)->getLineNo()
|
|
, ((XSDElementNSImpl*)elem)->getColumnNo() );
|
|
annot->setSystemId(fSchemaInfo->getCurrentSchemaURL());
|
|
return annot;
|
|
}
|
|
|
|
class AnnotationErrorReporter : public XMLErrorReporter
|
|
{
|
|
public:
|
|
AnnotationErrorReporter(XMLErrorReporter* chainedErrorReporter)
|
|
{
|
|
fErrorReporter = chainedErrorReporter;
|
|
setSystemIdAndPosition(NULL, 0, 0);
|
|
}
|
|
|
|
void setSystemIdAndPosition(const XMLCh* systemId, XMLFileLoc line, XMLFileLoc column)
|
|
{
|
|
fSystemId=systemId;
|
|
fLine=line;
|
|
fColumn=column;
|
|
}
|
|
|
|
virtual void error
|
|
(
|
|
const unsigned int errCode
|
|
, const XMLCh* const errDomain
|
|
, const ErrTypes type
|
|
, const XMLCh* const errorText
|
|
, const XMLCh* const /*systemId*/
|
|
, const XMLCh* const publicId
|
|
, const XMLFileLoc lineNum
|
|
, const XMLFileLoc colNum
|
|
)
|
|
{
|
|
if(fErrorReporter)
|
|
fErrorReporter->error(errCode, errDomain, type, errorText, fSystemId, publicId, fLine+lineNum-1, lineNum==1?fColumn+colNum:colNum);
|
|
}
|
|
|
|
virtual void resetErrors() {}
|
|
|
|
protected:
|
|
XMLErrorReporter* fErrorReporter;
|
|
const XMLCh* fSystemId;
|
|
XMLFileLoc fLine, fColumn;
|
|
};
|
|
|
|
void TraverseSchema::validateAnnotations() {
|
|
|
|
MemoryManager *memMgr = fMemoryManager;
|
|
RefHashTableOfEnumerator<XSAnnotation, PtrHasher> xsAnnotationEnum = RefHashTableOfEnumerator<XSAnnotation, PtrHasher> (fSchemaGrammar->getAnnotations(), false, memMgr);
|
|
XSAnnotation& xsAnnot = xsAnnotationEnum.nextElement();
|
|
XSAnnotation* nextAnnot;
|
|
|
|
// create schema grammar
|
|
SchemaGrammar *grammar = new (memMgr) SchemaGrammar(memMgr);
|
|
grammar->setComplexTypeRegistry(new (memMgr) RefHashTableOf<ComplexTypeInfo>(29, memMgr));
|
|
grammar->setGroupInfoRegistry(new (memMgr) RefHashTableOf<XercesGroupInfo>(13, memMgr));
|
|
grammar->setAttGroupInfoRegistry(new (memMgr) RefHashTableOf<XercesAttGroupInfo>(13, memMgr));
|
|
grammar->setAttributeDeclRegistry(new (memMgr) RefHashTableOf<XMLAttDef>(29, memMgr));
|
|
grammar->setValidSubstitutionGroups(new (memMgr) RefHash2KeysTableOf<ElemVector>(29, memMgr));
|
|
grammar->setTargetNamespace(SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
|
|
XMLSchemaDescription* gramDesc = (XMLSchemaDescription*) grammar->getGrammarDescription();
|
|
gramDesc->setTargetNamespace(SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
|
|
|
|
// setup components of annotation grammar
|
|
SchemaElementDecl* annotElemDecl = new (memMgr) SchemaElementDecl
|
|
(
|
|
XMLUni::fgZeroLenString , SchemaSymbols::fgELT_ANNOTATION
|
|
, fURIStringPool->addOrFind(SchemaSymbols::fgURI_SCHEMAFORSCHEMA)
|
|
, SchemaElementDecl::Mixed_Complex, Grammar::TOP_LEVEL_SCOPE , memMgr
|
|
);
|
|
annotElemDecl->setCreateReason(XMLElementDecl::Declared);
|
|
grammar->putElemDecl(annotElemDecl);
|
|
|
|
ComplexTypeInfo* complexType = new (memMgr) ComplexTypeInfo(memMgr);
|
|
complexType->setAnonymous();
|
|
complexType->setContentType(SchemaElementDecl::Mixed_Complex);
|
|
annotElemDecl->setComplexTypeInfo(complexType);
|
|
|
|
fBuffer.set(SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
|
|
fBuffer.append(chComma);
|
|
fBuffer.append(chLatin_C);
|
|
fBuffer.append(chDigit_0);
|
|
const XMLCh* fullName = fStringPool->getValueForId(fStringPool->addOrFind(fBuffer.getRawBuffer()));
|
|
grammar->getComplexTypeRegistry()->put((void*) fullName, complexType);
|
|
complexType->setTypeName(fullName);
|
|
complexType->setAttWildCard
|
|
(
|
|
new (memMgr) SchemaAttDef
|
|
(
|
|
XMLUni::fgZeroLenString, XMLUni::fgZeroLenString,
|
|
fEmptyNamespaceURI, XMLAttDef::Any_Any,
|
|
XMLAttDef::ProcessContents_Lax, memMgr
|
|
)
|
|
);
|
|
|
|
SchemaElementDecl* appInfoElemDecl = new (memMgr) SchemaElementDecl
|
|
(
|
|
XMLUni::fgZeroLenString , SchemaSymbols::fgELT_APPINFO
|
|
, fURIStringPool->addOrFind(SchemaSymbols::fgURI_SCHEMAFORSCHEMA)
|
|
, SchemaElementDecl::Any, Grammar::TOP_LEVEL_SCOPE , memMgr
|
|
);
|
|
|
|
appInfoElemDecl->setCreateReason(XMLElementDecl::Declared);
|
|
appInfoElemDecl->setAttWildCard
|
|
(
|
|
new (memMgr) SchemaAttDef
|
|
(
|
|
XMLUni::fgZeroLenString, XMLUni::fgZeroLenString,
|
|
fEmptyNamespaceURI, XMLAttDef::Any_Any,
|
|
XMLAttDef::ProcessContents_Lax, memMgr
|
|
)
|
|
);
|
|
grammar->putElemDecl(appInfoElemDecl);
|
|
complexType->addElement(appInfoElemDecl);
|
|
|
|
SchemaElementDecl* docElemDecl = new (memMgr) SchemaElementDecl
|
|
(
|
|
XMLUni::fgZeroLenString , SchemaSymbols::fgELT_DOCUMENTATION
|
|
, fURIStringPool->addOrFind(SchemaSymbols::fgURI_SCHEMAFORSCHEMA)
|
|
, SchemaElementDecl::Any, Grammar::TOP_LEVEL_SCOPE , memMgr
|
|
);
|
|
|
|
docElemDecl->setCreateReason(XMLElementDecl::Declared);
|
|
docElemDecl->setAttWildCard
|
|
(
|
|
new (memMgr) SchemaAttDef
|
|
(
|
|
XMLUni::fgZeroLenString, XMLUni::fgZeroLenString,
|
|
fEmptyNamespaceURI, XMLAttDef::Any_Any,
|
|
XMLAttDef::ProcessContents_Lax, memMgr
|
|
)
|
|
);
|
|
grammar->putElemDecl(docElemDecl);
|
|
complexType->addElement(docElemDecl);
|
|
|
|
ContentSpecNode* left = new (memMgr) ContentSpecNode(appInfoElemDecl, memMgr);
|
|
ContentSpecNode* right = new (memMgr) ContentSpecNode(docElemDecl, memMgr);
|
|
ContentSpecNode* root = new (memMgr) ContentSpecNode(ContentSpecNode::ModelGroupChoice
|
|
, left
|
|
, right
|
|
, true
|
|
, true
|
|
, memMgr);
|
|
root->setMinOccurs(0);
|
|
root->setMaxOccurs(SchemaSymbols::XSD_UNBOUNDED);
|
|
complexType->setContentSpec(root);
|
|
|
|
// create input source to scan
|
|
MemBufInputSource* memBufIS = new (memMgr) MemBufInputSource
|
|
(
|
|
(const XMLByte*)xsAnnot.getAnnotationString()
|
|
, XMLString::stringLen(xsAnnot.getAnnotationString())*sizeof(XMLCh)
|
|
, SchemaSymbols::fgELT_ANNOTATION
|
|
, false
|
|
, memMgr
|
|
);
|
|
Janitor<MemBufInputSource> janMemBuf(memBufIS);
|
|
memBufIS->setEncoding(XMLUni::fgXMLChEncodingString);
|
|
memBufIS->setCopyBufToStream(false);
|
|
|
|
XSAXMLScanner *scanner = new (memMgr) XSAXMLScanner
|
|
(
|
|
fGrammarResolver, fURIStringPool, grammar, memMgr
|
|
);
|
|
Janitor<XSAXMLScanner> janScanner(scanner);
|
|
|
|
AnnotationErrorReporter annErrReporter(fErrorReporter);
|
|
scanner->setErrorReporter(&annErrReporter);
|
|
|
|
XMLFileLoc line, col;
|
|
xsAnnot.getLineCol(line, col);
|
|
annErrReporter.setSystemIdAndPosition(xsAnnot.getSystemId(), line, col);
|
|
scanner->scanDocument(*memBufIS);
|
|
|
|
nextAnnot = xsAnnot.getNext();
|
|
|
|
while (nextAnnot || xsAnnotationEnum.hasMoreElements())
|
|
{
|
|
if (nextAnnot) {
|
|
memBufIS->resetMemBufInputSource((const XMLByte*)nextAnnot->getAnnotationString()
|
|
, XMLString::stringLen(nextAnnot->getAnnotationString())*sizeof(XMLCh));
|
|
nextAnnot->getLineCol(line, col);
|
|
annErrReporter.setSystemIdAndPosition(nextAnnot->getSystemId(), line, col);
|
|
nextAnnot = nextAnnot->getNext();
|
|
}
|
|
else {
|
|
XSAnnotation& xsAnnot = xsAnnotationEnum.nextElement();
|
|
memBufIS->resetMemBufInputSource((const XMLByte*)xsAnnot.getAnnotationString()
|
|
, XMLString::stringLen(xsAnnot.getAnnotationString())*sizeof(XMLCh));
|
|
xsAnnot.getLineCol(line, col);
|
|
annErrReporter.setSystemIdAndPosition(xsAnnot.getSystemId(), line, col);
|
|
nextAnnot = xsAnnot.getNext();
|
|
}
|
|
scanner->scanDocument(*memBufIS);
|
|
}
|
|
|
|
}
|
|
|
|
const XMLCh* TraverseSchema::getElementAttValue(const DOMElement* const elem,
|
|
const XMLCh* const attName,
|
|
const DatatypeValidator::ValidatorType attType /* = UnKnown */) {
|
|
|
|
DOMAttr* attNode = elem->getAttributeNode(attName);
|
|
|
|
if (attNode == 0) {
|
|
return 0;
|
|
}
|
|
|
|
const XMLCh* attValue = attNode->getValue();
|
|
|
|
if (attType < DatatypeValidator::ID) {
|
|
static bool bInitialized = false;
|
|
static short wsFacets[DatatypeValidator::ID] = {0};
|
|
if(!bInitialized)
|
|
{
|
|
bInitialized=true;
|
|
DVHashTable* registry = DatatypeValidatorFactory::getBuiltInRegistry();
|
|
wsFacets[DatatypeValidator::String] = registry->get(SchemaSymbols::fgDT_STRING)->getWSFacet();
|
|
wsFacets[DatatypeValidator::AnyURI] = registry->get(SchemaSymbols::fgDT_ANYURI)->getWSFacet();
|
|
wsFacets[DatatypeValidator::QName] = registry->get(SchemaSymbols::fgDT_QNAME)->getWSFacet();
|
|
wsFacets[DatatypeValidator::Name] = registry->get(SchemaSymbols::fgDT_NAME)->getWSFacet();
|
|
wsFacets[DatatypeValidator::NCName] = registry->get(SchemaSymbols::fgDT_NCNAME)->getWSFacet();
|
|
wsFacets[DatatypeValidator::Boolean] = registry->get(SchemaSymbols::fgDT_BOOLEAN)->getWSFacet();
|
|
wsFacets[DatatypeValidator::Float] = registry->get(SchemaSymbols::fgDT_FLOAT)->getWSFacet();
|
|
wsFacets[DatatypeValidator::Double] = registry->get(SchemaSymbols::fgDT_DOUBLE)->getWSFacet();
|
|
wsFacets[DatatypeValidator::Decimal] = registry->get(SchemaSymbols::fgDT_DECIMAL)->getWSFacet();
|
|
wsFacets[DatatypeValidator::HexBinary] = registry->get(SchemaSymbols::fgDT_HEXBINARY)->getWSFacet();
|
|
wsFacets[DatatypeValidator::Base64Binary]= registry->get(SchemaSymbols::fgDT_BASE64BINARY)->getWSFacet();
|
|
wsFacets[DatatypeValidator::Duration] = registry->get(SchemaSymbols::fgDT_DURATION)->getWSFacet();
|
|
wsFacets[DatatypeValidator::DateTime] = registry->get(SchemaSymbols::fgDT_DATETIME)->getWSFacet();
|
|
wsFacets[DatatypeValidator::Date] = registry->get(SchemaSymbols::fgDT_DATE)->getWSFacet();
|
|
wsFacets[DatatypeValidator::Time] = registry->get(SchemaSymbols::fgDT_TIME)->getWSFacet();
|
|
wsFacets[DatatypeValidator::MonthDay] = registry->get(SchemaSymbols::fgDT_MONTHDAY)->getWSFacet();
|
|
wsFacets[DatatypeValidator::YearMonth] = registry->get(SchemaSymbols::fgDT_YEARMONTH)->getWSFacet();
|
|
wsFacets[DatatypeValidator::Year] = registry->get(SchemaSymbols::fgDT_YEAR)->getWSFacet();
|
|
wsFacets[DatatypeValidator::Month] = registry->get(SchemaSymbols::fgDT_MONTH)->getWSFacet();
|
|
wsFacets[DatatypeValidator::Day] = registry->get(SchemaSymbols::fgDT_DAY)->getWSFacet();
|
|
}
|
|
short wsFacet = wsFacets[attType];
|
|
if((wsFacet == DatatypeValidator::REPLACE && !XMLString::isWSReplaced(attValue)) ||
|
|
(wsFacet == DatatypeValidator::COLLAPSE && !XMLString::isWSCollapsed(attValue)))
|
|
{
|
|
XMLCh* normalizedValue=XMLString::replicate(attValue, fMemoryManager);
|
|
ArrayJanitor<XMLCh> tempName(normalizedValue, fMemoryManager);
|
|
if(wsFacet == DatatypeValidator::REPLACE)
|
|
XMLString::replaceWS(normalizedValue, fMemoryManager);
|
|
else if(wsFacet == DatatypeValidator::COLLAPSE)
|
|
XMLString::collapseWS(normalizedValue, fMemoryManager);
|
|
if (!*normalizedValue)
|
|
return XMLUni::fgZeroLenString;
|
|
return fStringPool->getValueForId(fStringPool->addOrFind(normalizedValue));
|
|
}
|
|
}
|
|
|
|
return attValue;
|
|
}
|
|
|
|
XERCES_CPP_NAMESPACE_END
|
|
|
|
/**
|
|
* End of file TraverseSchema.cpp
|
|
*/
|