blob: 5c60175c603af5b1efb698c0fc0428c4e22cd951 [file] [log] [blame]
/*
* 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.
*/
/**
* This file contains code to build the DOM tree. It registers a document
* handler with the scanner. In these handler methods, appropriate DOM nodes
* are created and added to the DOM tree.
*
* $Id: DOMParser.cpp 568078 2007-08-21 11:43:25Z amassari $
*
*/
// ---------------------------------------------------------------------------
// Includes
// ---------------------------------------------------------------------------
#include <xercesc/internal/XMLScannerResolver.hpp>
#include <xercesc/sax/EntityResolver.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/sax/ErrorHandler.hpp>
#include <xercesc/sax/SAXParseException.hpp>
#include <xercesc/framework/XMLNotationDecl.hpp>
#include <xercesc/util/IOException.hpp>
#include <xercesc/framework/XMLValidator.hpp>
#include <xercesc/validators/common/GrammarResolver.hpp>
#include <xercesc/framework/XMLGrammarPool.hpp>
#include <xercesc/framework/XMLSchemaDescription.hpp>
#include <xercesc/util/Janitor.hpp>
#include "DOMParser.hpp"
#include "ElementImpl.hpp"
#include "AttrImpl.hpp"
#include "AttrNSImpl.hpp"
#include "TextImpl.hpp"
#include "DocumentImpl.hpp"
#include "DocumentTypeImpl.hpp"
#include "EntityImpl.hpp"
#include "NotationImpl.hpp"
#include "NamedNodeMapImpl.hpp"
#include "NodeIDMap.hpp"
#include <xercesc/validators/common/ContentSpecNode.hpp>
#include <xercesc/validators/DTD/DTDAttDefList.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>
#include <xercesc/util/XMLEntityResolver.hpp>
XERCES_CPP_NAMESPACE_BEGIN
// ---------------------------------------------------------------------------
// DOMParser: Constructors and Destructor
// ---------------------------------------------------------------------------
DOMParser::DOMParser( XMLValidator* const valToAdopt
, MemoryManager* const manager
, XMLGrammarPool* const gramPool) :
fToCreateXMLDeclTypeNode(false)
, fCreateEntityReferenceNodes(true)
, fIncludeIgnorableWhitespace(true)
, fParseInProgress(false)
, fWithinElement(false)
, fEntityResolver(0)
, fXMLEntityResolver(0)
, fErrorHandler(0)
, fPSVIHandler(0)
, fNodeStack(0)
, fScanner(0)
, fDocumentType(0)
, fGrammarResolver(0)
, fURIStringPool(0)
, fValidator(valToAdopt)
, fMemoryManager(manager)
, fGrammarPool(gramPool)
{
try
{
initialize();
}
catch(const OutOfMemoryException&)
{
throw;
}
catch(...)
{
cleanUp();
throw;
}
}
DOMParser::~DOMParser()
{
cleanUp();
}
// ---------------------------------------------------------------------------
// DOMParser: Initialize/CleanUp methods
// ---------------------------------------------------------------------------
void DOMParser::initialize()
{
// Create grammar resolver and URI string pool to pass to the scanner
fGrammarResolver = new (fMemoryManager) GrammarResolver(fGrammarPool, fMemoryManager);
fURIStringPool = fGrammarResolver->getStringPool();
// Create a scanner and tell it what validator to use. Then set us
// as the document event handler so we can fill the DOM document.
fScanner = XMLScannerResolver::getDefaultScanner(fValidator, fGrammarResolver, fMemoryManager);
fScanner->setDocHandler(this);
fScanner->setDocTypeHandler(this);
fScanner->setURIStringPool(fURIStringPool);
fNodeStack = new (fMemoryManager) ValueStackOf<DOM_Node>(64, fMemoryManager, true);
this->reset();
}
void DOMParser::cleanUp()
{
delete fNodeStack;
delete fScanner;
delete fGrammarResolver;
// grammar pool must do this
//delete fURIStringPool;
if (fValidator)
delete fValidator;
}
void DOMParser::reset()
{
//
// Note: DOM Documents are reference counted. Doing this assignment
// will cause the old one to go away unless application code is also
// holding a reference to it.
//
fDocument = DOM_Document::createDocument(fMemoryManager);
resetDocType();
fCurrentParent = 0;
fCurrentNode = 0;
fParseInProgress = false;
fWithinElement = false;
fNodeStack->removeAllElements();
};
// ---------------------------------------------------------------------------
// DOMParser: Getter methods
// ---------------------------------------------------------------------------
const XMLValidator& DOMParser::getValidator() const
{
return *fScanner->getValidator();
}
bool DOMParser::getDoNamespaces() const
{
return fScanner->getDoNamespaces();
}
bool DOMParser::getExitOnFirstFatalError() const
{
return fScanner->getExitOnFirstFatal();
}
bool DOMParser::getValidationConstraintFatal() const
{
return fScanner->getValidationConstraintFatal();
}
DOMParser::ValSchemes DOMParser::getValidationScheme() const
{
const XMLScanner::ValSchemes scheme = fScanner->getValidationScheme();
if (scheme == XMLScanner::Val_Always)
return Val_Always;
else if (scheme == XMLScanner::Val_Never)
return Val_Never;
return Val_Auto;
}
bool DOMParser::getDoSchema() const
{
return fScanner->getDoSchema();
}
bool DOMParser::getValidationSchemaFullChecking() const
{
return fScanner->getValidationSchemaFullChecking();
}
bool DOMParser::getIdentityConstraintChecking() const
{
return fScanner->getIdentityConstraintChecking();
}
int DOMParser::getErrorCount() const
{
return fScanner->getErrorCount();
}
XMLCh* DOMParser::getExternalSchemaLocation() const
{
return fScanner->getExternalSchemaLocation();
}
XMLCh* DOMParser::getExternalNoNamespaceSchemaLocation() const
{
return fScanner->getExternalNoNamespaceSchemaLocation();
}
bool DOMParser::isCachingGrammarFromParse() const
{
return fScanner->isCachingGrammarFromParse();
}
bool DOMParser::isUsingCachedGrammarInParse() const
{
return fScanner->isUsingCachedGrammarInParse();
}
Grammar* DOMParser::getGrammar(const XMLCh* const nameSpaceKey)
{
return fGrammarResolver->getGrammar(nameSpaceKey);
}
Grammar* DOMParser::getRootGrammar()
{
return fScanner->getRootGrammar();
}
const XMLCh* DOMParser::getURIText(unsigned int uriId) const
{
return fScanner->getURIText(uriId);
}
bool DOMParser::getCalculateSrcOfs() const
{
return fScanner->getCalculateSrcOfs();
}
bool DOMParser::getStandardUriConformant() const
{
return fScanner->getStandardUriConformant();
}
unsigned int DOMParser::getSrcOffset() const
{
return fScanner->getSrcOffset();
}
// ---------------------------------------------------------------------------
// DOMParser: Setter methods
// ---------------------------------------------------------------------------
void DOMParser::setDoNamespaces(const bool newState)
{
fScanner->setDoNamespaces(newState);
}
void DOMParser::setErrorHandler(ErrorHandler* const handler)
{
fErrorHandler = handler;
if (fErrorHandler) {
fScanner->setErrorReporter(this);
fScanner->setErrorHandler(fErrorHandler);
}
else {
fScanner->setErrorReporter(0);
fScanner->setErrorHandler(0);
}
}
void DOMParser::setPSVIHandler(PSVIHandler* const handler)
{
fPSVIHandler = handler;
if (fPSVIHandler) {
fScanner->setPSVIHandler(fPSVIHandler);
}
else {
fScanner->setPSVIHandler(0);
}
}
void DOMParser::setEntityResolver(EntityResolver* const handler)
{
fEntityResolver = handler;
if (fEntityResolver) {
fScanner->setEntityHandler(this);
fXMLEntityResolver = 0;
}
else {
fScanner->setEntityHandler(0);
}
}
void DOMParser::setXMLEntityResolver(XMLEntityResolver* const handler)
{
fXMLEntityResolver = handler;
if (fXMLEntityResolver) {
fEntityResolver = 0;
fScanner->setEntityHandler(this);
}
else {
fScanner->setEntityHandler(0);
}
}
void DOMParser::setExitOnFirstFatalError(const bool newState)
{
fScanner->setExitOnFirstFatal(newState);
}
void DOMParser::setValidationConstraintFatal(const bool newState)
{
fScanner->setValidationConstraintFatal(newState);
}
void DOMParser::setValidationScheme(const ValSchemes newScheme)
{
if (newScheme == Val_Never)
fScanner->setValidationScheme(XMLScanner::Val_Never);
else if (newScheme == Val_Always)
fScanner->setValidationScheme(XMLScanner::Val_Always);
else
fScanner->setValidationScheme(XMLScanner::Val_Auto);
}
void DOMParser::setDoSchema(const bool newState)
{
fScanner->setDoSchema(newState);
}
void DOMParser::setValidationSchemaFullChecking(const bool schemaFullChecking)
{
fScanner->setValidationSchemaFullChecking(schemaFullChecking);
}
void DOMParser::setIdentityConstraintChecking(const bool identityConstraintChecking)
{
fScanner->setIdentityConstraintChecking(identityConstraintChecking);
}
void DOMParser::setExternalSchemaLocation(const XMLCh* const schemaLocation)
{
fScanner->setExternalSchemaLocation(schemaLocation);
}
void DOMParser::setExternalNoNamespaceSchemaLocation(const XMLCh* const noNamespaceSchemaLocation)
{
fScanner->setExternalNoNamespaceSchemaLocation(noNamespaceSchemaLocation);
}
void DOMParser::setExternalSchemaLocation(const char* const schemaLocation)
{
fScanner->setExternalSchemaLocation(schemaLocation);
}
void DOMParser::setExternalNoNamespaceSchemaLocation(const char* const noNamespaceSchemaLocation)
{
fScanner->setExternalNoNamespaceSchemaLocation(noNamespaceSchemaLocation);
}
void DOMParser::cacheGrammarFromParse(const bool newState)
{
fScanner->cacheGrammarFromParse(newState);
if (newState)
fScanner->useCachedGrammarInParse(newState);
}
void DOMParser::useCachedGrammarInParse(const bool newState)
{
if (newState || !fScanner->isCachingGrammarFromParse())
fScanner->useCachedGrammarInParse(newState);
}
void DOMParser::setCalculateSrcOfs(const bool newState)
{
fScanner->setCalculateSrcOfs(newState);
}
void DOMParser::setStandardUriConformant(const bool newState)
{
fScanner->setStandardUriConformant(newState);
}
void DOMParser::useScanner(const XMLCh* const scannerName)
{
XMLScanner* tempScanner = XMLScannerResolver::resolveScanner
(
scannerName
, fValidator
, fGrammarResolver
, fMemoryManager
);
if (tempScanner) {
tempScanner->setParseSettings(fScanner);
tempScanner->setURIStringPool(fURIStringPool);
delete fScanner;
fScanner = tempScanner;
}
}
// ---------------------------------------------------------------------------
// DOMParser: Parsing methods
// ---------------------------------------------------------------------------
void DOMParser::parse(const InputSource& source)
{
// Avoid multiple entrance
if (fParseInProgress)
ThrowXMLwithMemMgr(IOException, XMLExcepts::Gen_ParseInProgress, fMemoryManager);
try
{
fParseInProgress = true;
fScanner->scanDocument(source);
fParseInProgress = false;
}
catch(const OutOfMemoryException&)
{
throw;
}
catch(...)
{
fParseInProgress = false;
throw;
}
}
void DOMParser::parse(const XMLCh* const systemId)
{
// Avoid multiple entrance
if (fParseInProgress)
ThrowXMLwithMemMgr(IOException, XMLExcepts::Gen_ParseInProgress, fMemoryManager);
try
{
fParseInProgress = true;
fScanner->scanDocument(systemId);
fParseInProgress = false;
}
catch(const OutOfMemoryException&)
{
throw;
}
catch(...)
{
fParseInProgress = false;
throw;
}
}
void DOMParser::parse(const char* const systemId)
{
// Avoid multiple entrance
if (fParseInProgress)
ThrowXMLwithMemMgr(IOException, XMLExcepts::Gen_ParseInProgress, fMemoryManager);
try
{
fParseInProgress = true;
fScanner->scanDocument(systemId);
fParseInProgress = false;
}
catch(const OutOfMemoryException&)
{
throw;
}
catch(...)
{
fParseInProgress = false;
throw;
}
}
// ---------------------------------------------------------------------------
// DOMParser: Progressive parse methods
// ---------------------------------------------------------------------------
bool DOMParser::parseFirst( const XMLCh* const systemId
, XMLPScanToken& toFill)
{
//
// Avoid multiple entrance. We cannot enter here while a regular parse
// is in progress.
//
if (fParseInProgress)
ThrowXMLwithMemMgr(IOException, XMLExcepts::Gen_ParseInProgress, fMemoryManager);
return fScanner->scanFirst(systemId, toFill);
}
bool DOMParser::parseFirst( const char* const systemId
, XMLPScanToken& toFill)
{
//
// Avoid multiple entrance. We cannot enter here while a regular parse
// is in progress.
//
if (fParseInProgress)
ThrowXMLwithMemMgr(IOException, XMLExcepts::Gen_ParseInProgress, fMemoryManager);
return fScanner->scanFirst(systemId, toFill);
}
bool DOMParser::parseFirst( const InputSource& source
, XMLPScanToken& toFill)
{
//
// Avoid multiple entrance. We cannot enter here while a regular parse
// is in progress.
//
if (fParseInProgress)
ThrowXMLwithMemMgr(IOException, XMLExcepts::Gen_ParseInProgress, fMemoryManager);
return fScanner->scanFirst(source, toFill);
}
bool DOMParser::parseNext(XMLPScanToken& token)
{
return fScanner->scanNext(token);
}
void DOMParser::parseReset(XMLPScanToken& token)
{
// Reset the scanner, and then reset the parser
fScanner->scanReset(token);
reset();
}
// ---------------------------------------------------------------------------
// DOMParser: Implementation of the XMLErrorReporter interface
// ---------------------------------------------------------------------------
void DOMParser::error( const unsigned int /*code*/
, const XMLCh* const /*msgDomain*/
, const XMLErrorReporter::ErrTypes errType
, const XMLCh* const errorText
, const XMLCh* const systemId
, const XMLCh* const publicId
, const XMLSSize_t lineNum
, const XMLSSize_t colNum)
{
SAXParseException toThrow = SAXParseException
(
errorText
, publicId
, systemId
, lineNum
, colNum
, fMemoryManager
);
//
// If there is an error handler registered, call it, otherwise ignore
// all but the fatal errors.
//
if (!fErrorHandler)
{
if (errType == XMLErrorReporter::ErrType_Fatal)
throw toThrow;
return;
}
if (errType == XMLErrorReporter::ErrType_Warning)
fErrorHandler->warning(toThrow);
else if (errType >= XMLErrorReporter::ErrType_Fatal)
fErrorHandler->fatalError(toThrow);
else
fErrorHandler->error(toThrow);
}
void DOMParser::resetErrors()
{
}
// ---------------------------------------------------------------------------
// DOMParser: Implementation of XMLEntityHandler interface
// ---------------------------------------------------------------------------
InputSource*
DOMParser::resolveEntity(const XMLCh* const publicId,
const XMLCh* const systemId,
const XMLCh* const /*baseURI*/)
{
//
// Just map it to the SAX entity resolver. If there is not one installed,
// return a null pointer to cause the default resolution.
//
if (fEntityResolver)
return fEntityResolver->resolveEntity(publicId, systemId);
return 0;
}
InputSource* DOMParser::resolveEntity(XMLResourceIdentifier* resourceIdentifier)
{
//
// Just map it to the SAX entity resolver. If there is not one installed,
// return a null pointer to cause the default resolution.
//
if (fEntityResolver)
return fEntityResolver->resolveEntity(resourceIdentifier->getPublicId(),
resourceIdentifier->getSystemId());
if (fXMLEntityResolver)
return fXMLEntityResolver->resolveEntity(resourceIdentifier);
return 0;
}
// ---------------------------------------------------------------------------
// DOMParser: Implementation of XMLDocumentHandler interface
// ---------------------------------------------------------------------------
void DOMParser::docCharacters( const XMLCh* const chars
, const unsigned int length
, const bool cdataSection)
{
// Ignore chars outside of content
if (!fWithinElement)
return;
if (cdataSection == true)
{
DOM_CDATASection node = fDocument.createCDATASection
(
DOMString(chars, length)
);
fCurrentParent.appendChild(node);
fCurrentNode = node;
}
else
{
if (fCurrentNode.getNodeType() == DOM_Node::TEXT_NODE)
{
DOM_Text node = (DOM_Text&)fCurrentNode;
node.appendData(DOMString(chars, length));
}
else
{
DOM_Text node = fDocument.createTextNode(DOMString(chars, length));
fCurrentParent.appendChild(node);
fCurrentNode = node;
}
}
}
void DOMParser::docComment(const XMLCh* const comment)
{
DOM_Comment dcom = fDocument.createComment(comment);
fCurrentParent.appendChild(dcom);
fCurrentNode = dcom;
}
void DOMParser::docPI( const XMLCh* const target
, const XMLCh* const data)
{
DOM_ProcessingInstruction pi = fDocument.createProcessingInstruction
(
target
, data
);
fCurrentParent.appendChild(pi);
fCurrentNode = pi;
}
void DOMParser::endEntityReference(const XMLEntityDecl& entDecl)
{
if (fCreateEntityReferenceNodes == true)
{
if (fCurrentParent.getNodeType() == DOM_Node::ENTITY_REFERENCE_NODE) {
// stick the parsed content of this entity reference into the entity definition node
EntityImpl* entity = (EntityImpl*)fDocumentType->entities->getNamedItem(entDecl.getName());
entity->setEntityRef((EntityReferenceImpl*)fCurrentParent.fImpl);
((DOM_EntityReference&)fCurrentParent).fImpl->setReadOnly(true, true);
}
fCurrentParent = fNodeStack->pop();
fCurrentNode = fCurrentParent;
}
}
void DOMParser::endElement( const XMLElementDecl& /*elemDecl*/
, const unsigned int /*urlId*/
, const bool /*isRoot*/
, const XMLCh* const /*elemPrefix*/)
{
fCurrentNode = fCurrentParent;
fCurrentParent = fNodeStack->pop();
// If we've hit the end of content, clear the flag
if (fNodeStack->empty())
fWithinElement = false;
}
void DOMParser::ignorableWhitespace(const XMLCh* const chars
, const unsigned int length
, const bool /*cdataSection*/)
{
// Ignore chars before the root element
if (!fWithinElement || !fIncludeIgnorableWhitespace)
return;
if (fCurrentNode.getNodeType() == DOM_Node::TEXT_NODE)
{
DOM_Text node = (DOM_Text&)fCurrentNode;
node.appendData(DOMString(chars, length));
}
else
{
DOM_Text node = fDocument.createTextNode(DOMString(chars, length));
TextImpl *text = (TextImpl *) node.fImpl;
text -> setIgnorableWhitespace(true);
fCurrentParent.appendChild(node);
fCurrentNode = node;
}
}
void DOMParser::resetDocument()
{
//
// The reset methods are called before a new parse event occurs.
// Reset this parsers state to clear out anything that may be left
// from a previous use, in particular the DOM document itself.
//
this->reset();
}
void DOMParser::startDocument()
{
// Just set the document as the current parent and current node
fCurrentParent = fDocument;
fCurrentNode = fDocument;
// set DOM error checking off
fDocument.setErrorChecking(false);
}
void DOMParser::endDocument()
{
// set DOM error checking back on
fDocument.setErrorChecking(true);
}
void DOMParser::startElement(const XMLElementDecl& elemDecl
, const unsigned int urlId
, const XMLCh* const elemPrefix
, const RefVectorOf<XMLAttr>& attrList
, const unsigned int attrCount
, const bool isEmpty
, const bool isRoot)
{
DOM_Element elem;
DocumentImpl *docImpl = (DocumentImpl *)fDocument.fImpl;
if (fScanner -> getDoNamespaces()) { //DOM Level 2, doNamespaces on
XMLBuffer buf(1023, fMemoryManager);
DOMString namespaceURI = 0;
DOMString elemQName = 0;
if (urlId != fScanner->getEmptyNamespaceId()) { //TagName has a prefix
fScanner->getURIText(urlId, buf); //get namespaceURI
namespaceURI = DOMString(buf.getRawBuffer());
if (elemPrefix && *elemPrefix) {
elemQName.appendData(elemPrefix);
elemQName.appendData(chColon);
}
}
elemQName.appendData(elemDecl.getBaseName());
elem = fDocument.createElementNS(namespaceURI, elemQName);
ElementImpl *elemImpl = (ElementImpl *) elem.fImpl;
for (unsigned int index = 0; index < attrCount; ++index) {
static const XMLCh XMLNS[] = {
chLatin_x, chLatin_m, chLatin_l, chLatin_n, chLatin_s, chNull
};
const XMLAttr* oneAttrib = attrList.elementAt(index);
unsigned int attrURIId = oneAttrib -> getURIId();
namespaceURI = 0;
if (!XMLString::compareString(oneAttrib -> getName(), XMLNS)) //for xmlns=...
attrURIId = fScanner->getXMLNSNamespaceId();
if (attrURIId != fScanner->getEmptyNamespaceId()) { //TagName has a prefix
fScanner->getURIText(attrURIId, buf); //get namespaceURI
namespaceURI = DOMString(buf.getRawBuffer());
}
AttrImpl *attr = elemImpl->setAttributeNS(namespaceURI, oneAttrib -> getQName(),
oneAttrib -> getValue());
// Attributes of type ID. If this is one, add it to the hashtable of IDs
// that is constructed for use by GetElementByID().
//
if (oneAttrib->getType()==XMLAttDef::ID)
{
if (docImpl->fNodeIDMap == 0)
docImpl->fNodeIDMap = new (fMemoryManager) NodeIDMap(500, fMemoryManager);
docImpl->fNodeIDMap->add(attr);
attr->isIdAttr(true);
}
attr->setSpecified(oneAttrib->getSpecified());
}
}
else { //DOM Level 1
elem = fDocument.createElement(elemDecl.getFullName());
ElementImpl *elemImpl = (ElementImpl *) elem.fImpl;
for (unsigned int index = 0; index < attrCount; ++index) {
const XMLAttr* oneAttrib = attrList.elementAt(index);
AttrImpl *attr = elemImpl->setAttribute(oneAttrib->getName(), oneAttrib->getValue());
attr->setSpecified(oneAttrib->getSpecified());
// Attributes of type ID. If this is one, add it to the hashtable of IDs
// that is constructed for use by GetElementByID().
//
if (oneAttrib->getType()==XMLAttDef::ID)
{
if (docImpl->fNodeIDMap == 0)
docImpl->fNodeIDMap = new (fMemoryManager) NodeIDMap(500, fMemoryManager);
docImpl->fNodeIDMap->add(attr);
attr->isIdAttr(true);
}
}
}
fCurrentParent.appendChild(elem);
fNodeStack->push(fCurrentParent);
fCurrentParent = elem;
fCurrentNode = elem;
fWithinElement = true;
// If an empty element, do end right now (no endElement() will be called)
if (isEmpty)
endElement(elemDecl, urlId, isRoot, elemPrefix);
}
void DOMParser::startEntityReference(const XMLEntityDecl& entDecl)
{
if (fCreateEntityReferenceNodes == true)
{
DOMString entName(entDecl.getName());
DOM_EntityReference er = fDocument.createEntityReference(entName);
//set the readOnly flag to false before appending node, will be reset in endEntityReference
er.fImpl->setReadOnly(false, true);
fCurrentParent.appendChild(er);
fNodeStack->push(fCurrentParent);
fCurrentParent = er;
fCurrentNode = er;
}
}
void DOMParser::XMLDecl(const XMLCh* const version
, const XMLCh* const encoding
, const XMLCh* const standalone
, const XMLCh* const /*actualEncStr*/)
{
//This is a non-standard extension to creating XMLDecl type nodes and attching to DOM Tree
// currently this flag it set to false unless user explicitly asks for it
// Needs to be revisited after W3C specs are laid out on this issue.
if (fToCreateXMLDeclTypeNode) {
DOMString ver(version);
DOMString enc(encoding);
DOMString isStd(standalone);
DOM_XMLDecl xmlDecl = fDocument.createXMLDecl(ver, enc, isStd);
fCurrentParent.appendChild(xmlDecl);
}
}
// ---------------------------------------------------------------------------
// DOMParser: Deprecated methods
// ---------------------------------------------------------------------------
bool DOMParser::getDoValidation() const
{
//
// We don't want to tie the public parser classes to the enum used
// by the scanner, so we use a separate one and map.
//
// DON'T mix the new and old methods!!
//
const XMLScanner::ValSchemes scheme = fScanner->getValidationScheme();
if (scheme == XMLScanner::Val_Always)
return true;
return false;
}
void DOMParser::setDoValidation(const bool newState)
{
fScanner->setDoValidation
(
newState ? XMLScanner::Val_Always : XMLScanner::Val_Never
);
}
//doctypehandler interfaces
void DOMParser::attDef
(
const DTDElementDecl& elemDecl
, const DTDAttDef& attDef
, const bool /*ignoring*/
)
{
if (fDocumentType->isIntSubsetReading())
{
DOMString attString;
if (elemDecl.hasAttDefs())
{
attString.appendData(chOpenAngle);
attString.appendData(chBang);
attString.appendData(XMLUni::fgAttListString);
attString.appendData(chSpace);
attString.appendData(elemDecl.getFullName());
attString.appendData(chSpace);
attString.appendData(attDef.getFullName());
// Get the type and display it
const XMLAttDef::AttTypes type = attDef.getType();
switch(type)
{
case XMLAttDef::CData :
attString.appendData(chSpace);
attString.appendData(XMLUni::fgCDATAString);
break;
case XMLAttDef::ID :
attString.appendData(chSpace);
attString.appendData(XMLUni::fgIDString);
break;
case XMLAttDef::IDRef :
attString.appendData(chSpace);
attString.appendData(XMLUni::fgIDRefString);
break;
case XMLAttDef::IDRefs :
attString.appendData(chSpace);
attString.appendData(XMLUni::fgIDRefsString);
break;
case XMLAttDef::Entity :
attString.appendData(chSpace);
attString.appendData(XMLUni::fgEntityString);
break;
case XMLAttDef::Entities :
attString.appendData(chSpace);
attString.appendData(XMLUni::fgEntitiesString);
break;
case XMLAttDef::NmToken :
attString.appendData(chSpace);
attString.appendData(XMLUni::fgNmTokenString);
break;
case XMLAttDef::NmTokens :
attString.appendData(chSpace);
attString.appendData(XMLUni::fgNmTokensString);
break;
case XMLAttDef::Notation :
attString.appendData(chSpace);
attString.appendData(XMLUni::fgNotationString);
break;
case XMLAttDef::Enumeration :
{
attString.appendData(chSpace);
// attString.appendData(XMLUni::fgEnumerationString);
const XMLCh* enumString = attDef.getEnumeration();
int length = XMLString::stringLen(enumString);
if (length > 0) {
DOMString anotherEnumString;
anotherEnumString.appendData(chOpenParen );
for(int i=0; i<length; i++) {
if (enumString[i] == chSpace)
anotherEnumString.appendData(chPipe);
else
anotherEnumString.appendData(enumString[i]);
}
anotherEnumString.appendData(chCloseParen);
attString.appendData(anotherEnumString);
}
}
break;
default:
// remaining types don't belong to a DTD
break;
}
//get te default types of the attlist
const XMLAttDef::DefAttTypes def = attDef.getDefaultType();
switch(def)
{
case XMLAttDef::Required :
attString.appendData(chSpace);
attString.appendData(XMLUni::fgRequiredString);
break;
case XMLAttDef::Implied :
attString.appendData(chSpace);
attString.appendData(XMLUni::fgImpliedString);
break;
case XMLAttDef::Fixed :
attString.appendData(chSpace);
attString.appendData(XMLUni::fgFixedString);
break;
default:
// remaining types don't belong to a DTD
break;
}
const XMLCh* defaultValue = attDef.getValue();
if (defaultValue != 0) {
attString.appendData(chSpace);
attString.appendData(chDoubleQuote);
attString.appendData(defaultValue);
attString.appendData(chDoubleQuote);
}
attString.appendData(chCloseAngle);
fDocumentType->internalSubset.appendData(attString);
}
}
}
void DOMParser::doctypeComment
(
const XMLCh* const comment
)
{
if (fDocumentType->isIntSubsetReading())
{
if (comment != 0)
{
DOMString comString;
comString.appendData(XMLUni::fgCommentString);
comString.appendData(chSpace);
comString.appendData(comment);
comString.appendData(chSpace);
comString.appendData(chDash);
comString.appendData(chDash);
comString.appendData(chCloseAngle);
fDocumentType->internalSubset.appendData(comString);
}
}
}
void DOMParser::doctypeDecl
(
const DTDElementDecl& elemDecl
, const XMLCh* const publicId
, const XMLCh* const systemId
, const bool /*hasIntSubset*/
, const bool /*hasExtSubset*/
)
{
DOM_DocumentType dt;
dt = fDocument.getImplementation().createDocumentType(elemDecl.getFullName(), publicId, systemId);
fDocumentType = (DocumentTypeImpl*)dt.fImpl;
((DocumentImpl*)fDocument.fImpl)->setDocumentType(fDocumentType);
}
void DOMParser::doctypePI
(
const XMLCh* const target
, const XMLCh* const data
)
{
if (fDocumentType->isIntSubsetReading())
{
//add these chars to internalSubset variable
DOMString pi;
pi.appendData(chOpenAngle);
pi.appendData(chQuestion);
pi.appendData(target);
pi.appendData(chSpace);
pi.appendData(data);
pi.appendData(chQuestion);
pi.appendData(chCloseAngle);
fDocumentType->internalSubset.appendData(pi);
}
}
void DOMParser::doctypeWhitespace
(
const XMLCh* const chars
, const unsigned int /*length*/
)
{
if (fDocumentType->isIntSubsetReading())
fDocumentType->internalSubset.appendData(chars);
}
void DOMParser::elementDecl
(
const DTDElementDecl& decl
, const bool /*isIgnored*/
)
{
if (fDocumentType->isIntSubsetReading())
{
DOMString elemDecl;
elemDecl.appendData(chOpenAngle);
elemDecl.appendData(chBang);
elemDecl.appendData(XMLUni::fgElemString);
elemDecl.appendData(chSpace);
elemDecl.appendData(decl.getFullName());
//get the ContentSpec information
const XMLCh* contentModel = decl.getFormattedContentModel();
if (contentModel != 0) {
elemDecl.appendData(chSpace);
elemDecl.appendData(contentModel);
}
elemDecl.appendData(chCloseAngle);
fDocumentType->internalSubset.appendData(elemDecl);
}
}
void DOMParser::endAttList
(
const DTDElementDecl& elemDecl
)
{
// this section sets up default attributes.
// default attribute nodes are stored in a NamedNodeMap DocumentTypeImpl::elements
// default attribute data attached to the document is used to conform to the
// DOM spec regarding creating element nodes & removing attributes with default values
// see DocumentTypeImpl
if (elemDecl.hasAttDefs())
{
XMLAttDefList* defAttrs = &elemDecl.getAttDefList();
XMLAttDef* attr = 0;
AttrImpl* insertAttr = 0;
DOM_Element dom_elem = fDocument.createElement(elemDecl.getFullName());
ElementImpl* elem = (ElementImpl*)(dom_elem.fImpl);
for(unsigned int i=0; i<defAttrs->getAttDefCount(); i++)
{
attr = &defAttrs->getAttDef(i);
if (attr->getValue() != null)
{
if (fScanner->getDoNamespaces())
{
// DOM Level 2 wants all namespace declaration attributes
// to be bound to "http://www.w3.org/2000/xmlns/"
// So as long as the XML parser doesn't do it, it needs to
// done here.
DOMString qualifiedName = attr->getFullName();
int index = DocumentImpl::indexofQualifiedName(qualifiedName);
XMLBuffer buf(1023, fMemoryManager);
static const XMLCh XMLNS[] = {
chLatin_x, chLatin_m, chLatin_l, chLatin_n, chLatin_s, chNull};
if (index > 0) {
// there is prefix
// map to XML URI for all cases except when prefix == "xmlns"
DOMString prefix = qualifiedName.substringData(0, index);
if (prefix.equals(XMLNS))
buf.append(XMLUni::fgXMLNSURIName);
else
buf.append(XMLUni::fgXMLURIName);
}
else {
// No prefix
if (qualifiedName.equals(XMLNS))
buf.append(XMLUni::fgXMLNSURIName);
}
insertAttr = new (fMemoryManager) AttrNSImpl((DocumentImpl*)fDocument.fImpl,
DOMString(buf.getRawBuffer()), // NameSpaceURI
qualifiedName); // qualified name
}
else
{
// Namespaces is turned off...
insertAttr = new (fMemoryManager) AttrImpl((DocumentImpl*)fDocument.fImpl, attr->getFullName());
}
insertAttr->setValue(attr->getValue());
// memory leak here
AttrImpl * previousAttr = elem->setAttributeNode(insertAttr);
if ( previousAttr != 0 && previousAttr->nodeRefCount ==0)
NodeImpl::deleteIf(previousAttr);
insertAttr->setSpecified(false);
}
}
ElementImpl *previousElem = (ElementImpl *)
fDocumentType->getElements()->setNamedItem( elem );
//
// If this new element is replacing an element node that was already
// in the element named node map, we need to delete the original
// element node, assuming no-one else was referencing it.
//
if (previousElem != 0 && previousElem->nodeRefCount == 0)
NodeImpl::deleteIf(previousElem);
}
}
void DOMParser::endIntSubset()
{
fDocumentType->intSubsetReading = false;
}
void DOMParser::endExtSubset()
{
}
void DOMParser::entityDecl
(
const DTDEntityDecl& entityDecl
, const bool /*isPEDecl*/
, const bool /*isIgnored*/
)
{
EntityImpl* entity = ((DocumentImpl*)fDocument.fImpl)->createEntity(entityDecl.getName());
entity->setPublicId(entityDecl.getPublicId());
entity->setSystemId(entityDecl.getSystemId());
entity->setNotationName(entityDecl.getNotationName());
EntityImpl *previousDef = (EntityImpl *)
fDocumentType->entities->setNamedItem( entity );
//
// If this new entity node is replacing an entity node that was already
// in the entities named node map (happens if documents redefine the
// predefined entited such as lt), we need to delete the original
// entitiy node, assuming no-one else was referencing it.
//
if (previousDef != 0 && previousDef->nodeRefCount == 0)
NodeImpl::deleteIf(previousDef);
if (fDocumentType->isIntSubsetReading())
{
//add thes chars to internalSubset variable
DOMString entityName;
entityName.appendData(chOpenAngle);
entityName.appendData(chBang);
entityName.appendData(XMLUni::fgEntityString);
entityName.appendData(chSpace);
entityName.appendData(entityDecl.getName());
DOMString id = entity->getPublicId();
if (id != 0) {
entityName.appendData(chSpace);
entityName.appendData(XMLUni::fgPubIDString);
entityName.appendData(chSpace);
entityName.appendData(chDoubleQuote);
entityName.appendData(id);
entityName.appendData(chDoubleQuote);
}
id = entity->getSystemId();
if (id != 0) {
entityName.appendData(chSpace);
entityName.appendData(XMLUni::fgSysIDString);
entityName.appendData(chSpace);
entityName.appendData(chDoubleQuote);
entityName.appendData(id);
entityName.appendData(chDoubleQuote);
}
id = entity->getNotationName();
if (id != 0) {
entityName.appendData(chSpace);
entityName.appendData(XMLUni::fgNDATAString);
entityName.appendData(chSpace);
entityName.appendData(chDoubleQuote);
entityName.appendData(id);
entityName.appendData(chDoubleQuote);
}
id = entityDecl.getValue();
if (id !=0) {
entityName.appendData(chSpace);
entityName.appendData(chDoubleQuote);
entityName.appendData(id);
entityName.appendData(chDoubleQuote);
}
entityName.appendData(chCloseAngle);
fDocumentType->internalSubset.appendData(entityName);
}
}
void DOMParser::resetDocType()
{
fDocumentType = null;
}
void DOMParser::notationDecl
(
const XMLNotationDecl& notDecl
, const bool /*isIgnored*/
)
{
NotationImpl* notation = ((DocumentImpl*)fDocument.fImpl)->createNotation(notDecl.getName());
notation->setPublicId(notDecl.getPublicId());
notation->setSystemId(notDecl.getSystemId());
NotationImpl *previousNot = (NotationImpl *)
fDocumentType->notations->setNamedItem( notation );
//
// If this new notation is replacing a notation node that was already
// in the notation named node map, we need to delete the original
// notation node, assuming no-one else was referencing it.
//
if (previousNot != 0 && previousNot->nodeRefCount == 0)
NodeImpl::deleteIf(previousNot);
}
void DOMParser::startAttList
(
const DTDElementDecl& /*elemDecl*/
)
{
}
void DOMParser::startIntSubset()
{
fDocumentType->intSubsetReading = true;
}
void DOMParser::startExtSubset()
{
}
void DOMParser::TextDecl
(
const XMLCh* const /*versionStr*/
, const XMLCh* const /*encodingStr*/
)
{
}
// ---------------------------------------------------------------------------
// DOMParser: Grammar preparsing methods
// ---------------------------------------------------------------------------
Grammar* DOMParser::loadGrammar(const char* const systemId,
const short grammarType,
const bool toCache)
{
// Avoid multiple entrance
if (fParseInProgress)
ThrowXMLwithMemMgr(IOException, XMLExcepts::Gen_ParseInProgress, fMemoryManager);
Grammar* grammar = 0;
try
{
fParseInProgress = true;
grammar = fScanner->loadGrammar(systemId, grammarType, toCache);
fParseInProgress = false;
}
catch(const OutOfMemoryException&)
{
throw;
} catch(...)
{
fParseInProgress = false;
throw;
}
return grammar;
}
Grammar* DOMParser::loadGrammar(const XMLCh* const systemId,
const short grammarType,
const bool toCache)
{
// Avoid multiple entrance
if (fParseInProgress)
ThrowXMLwithMemMgr(IOException, XMLExcepts::Gen_ParseInProgress, fMemoryManager);
Grammar* grammar = 0;
try
{
fParseInProgress = true;
grammar = fScanner->loadGrammar(systemId, grammarType, toCache);
fParseInProgress = false;
}
catch(const OutOfMemoryException&)
{
throw;
}
catch(...)
{
fParseInProgress = false;
throw;
}
return grammar;
}
Grammar* DOMParser::loadGrammar(const InputSource& source,
const short grammarType,
const bool toCache)
{
// Avoid multiple entrance
if (fParseInProgress)
ThrowXMLwithMemMgr(IOException, XMLExcepts::Gen_ParseInProgress, fMemoryManager);
Grammar* grammar = 0;
try
{
fParseInProgress = true;
grammar = fScanner->loadGrammar(source, grammarType, toCache);
fParseInProgress = false;
}
catch(const OutOfMemoryException&)
{
throw;
}
catch(...)
{
fParseInProgress = false;
throw;
}
return grammar;
}
void DOMParser::resetCachedGrammarPool()
{
fGrammarResolver->resetCachedGrammar();
}
XERCES_CPP_NAMESPACE_END