blob: 109be5f6cb81d292455adafbaf6271ddfca66713 [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.
*/
// Class header file
#include "StylesheetRoot.hpp"
#include <algorithm>
#include <memory>
#include <xalanc/XalanDOM/XalanDocumentFragment.hpp>
#include <xalanc/PlatformSupport/AttributeListImpl.hpp>
#include <xalanc/PlatformSupport/PrintWriter.hpp>
#include <xalanc/PlatformSupport/StringTokenizer.hpp>
#include <xalanc/PlatformSupport/XalanMessageLoader.hpp>
#include <xalanc/DOMSupport/DOMServices.hpp>
#include <xalanc/XPath/XalanQNameByReference.hpp>
#include <xalanc/XPath/XPathFactory.hpp>
#include <xalanc/XPath/XPathProcessor.hpp>
#include <xalanc/XMLSupport/FormatterToHTML.hpp>
#include <xalanc/XMLSupport/FormatterToText.hpp>
#include <xalanc/XMLSupport/FormatterToXML.hpp>
#include "Constants.hpp"
#include "ElemApplyTemplates.hpp"
#include "ElemAttributeSet.hpp"
#include "ElemTemplate.hpp"
#include "ElemValueOf.hpp"
#include "KeyTable.hpp"
#include "StylesheetConstructionContext.hpp"
#include "StylesheetExecutionContext.hpp"
#include "TraceListener.hpp"
#include "XSLTResultTarget.hpp"
//#define XALAN_VQ_SPECIAL_TRACE
#if defined(XALAN_VQ_SPECIAL_TRACE)
#include "C:/Program Files/Rational/Quantify/pure.h"
#endif
namespace XALAN_CPP_NAMESPACE {
StylesheetRoot::StylesheetRoot(
const XalanDOMString& baseIdentifier,
StylesheetConstructionContext& constructionContext) :
Stylesheet(*this,
baseIdentifier,
constructionContext),
m_version(constructionContext.getMemoryManager()),
m_indentResult(eIndentNoImplicit),
m_encoding(constructionContext.getMemoryManager()),
m_mediatype(constructionContext.getMemoryManager()),
m_doctypeSystem(constructionContext.getMemoryManager()),
m_doctypePublic(constructionContext.getMemoryManager()),
m_omitxmlDecl(false),
m_standalone(constructionContext.getMemoryManager()),
m_resultNameSpaceURL(constructionContext.getMemoryManager()),
m_outputMethod(FormatterListener::OUTPUT_METHOD_NONE),
m_cdataSectionElems(constructionContext.getMemoryManager()),
m_hasCDATASectionElems(false),
m_importStack(constructionContext.getMemoryManager()),
m_defaultTextRule(0),
m_defaultRule(0),
m_defaultRootRule(0),
m_needToBuildKeysTable(false),
m_outputEscapeURLs(true),
m_indentAmount(-1),
m_omitMETATag(false),
m_elemNumberNextID(0),
m_attributeSetsMap(constructionContext.getMemoryManager()),
m_hasStripOrPreserveSpace(false)
{
// Our base class has already resolved the URI and pushed it on
// the back of the include stack, so get it from there...
assert(getIncludeStack().empty() == false);
m_importStack.push_back(getIncludeStack().back());
}
StylesheetRoot*
StylesheetRoot::create(
MemoryManager& theManager,
const XalanDOMString& baseIdentifier,
StylesheetConstructionContext& constructionContext)
{
typedef StylesheetRoot ThisType;
XalanAllocationGuard theGuard(theManager, theManager.allocate(sizeof(ThisType)));
ThisType* const theResult =
new (theGuard.get()) ThisType(
baseIdentifier,
constructionContext);
theGuard.release();
return theResult;
}
StylesheetRoot::~StylesheetRoot()
{
}
void
StylesheetRoot::postConstruction(StylesheetConstructionContext& constructionContext)
{
// Chain-up first...
Stylesheet::postConstruction(constructionContext);
initDefaultRule(constructionContext);
{
AttributeSetMapType::iterator theCurrentMap = m_attributeSetsMap.begin();
const AttributeSetMapType::iterator theEndMap = m_attributeSetsMap.end();
while(theCurrentMap != theEndMap)
{
AttributeSetVectorType::iterator theCurrentVector = (*theCurrentMap).second.begin();
const AttributeSetVectorType::iterator theEndVector = (*theCurrentMap).second.end();
while(theCurrentVector != theEndVector)
{
(*theCurrentVector)->postConstruction(constructionContext, getNamespacesHandler());
++theCurrentVector;
}
++theCurrentMap;
}
}
// We may need to build keys, since we may have inherited them from
// our imports.
if (m_needToBuildKeysTable == false &&
m_keyDeclarations.empty() == false)
{
m_needToBuildKeysTable = true;
}
// cdata-section-elements only applies to the XML output method...
if (m_outputMethod != FormatterListener::OUTPUT_METHOD_XML &&
m_outputMethod != FormatterListener::OUTPUT_METHOD_NONE)
{
m_cdataSectionElems.clear();
}
else if (m_cdataSectionElems.empty() == false)
{
using std::sort;
sort(
m_cdataSectionElems.begin(),
m_cdataSectionElems.end(),
pointer_less<XalanQName>());
m_hasCDATASectionElems = true;
}
m_hasStripOrPreserveSpace = m_whitespaceElements.empty() == false;
}
typedef StylesheetExecutionContext::GetCachedString GetCachedString;
void
StylesheetRoot::process(
XalanNode* sourceTree,
XSLTResultTarget& outputTarget,
StylesheetExecutionContext& executionContext) const
{
assert(m_defaultRule != 0);
assert(m_defaultTextRule != 0);
assert(m_defaultRootRule != 0);
// Find the root pattern in the XSL.
const ElemTemplateElement* rootRule =
findTemplate(executionContext, sourceTree);
if(0 == rootRule)
{
rootRule = m_defaultRootRule;
}
assert(rootRule != 0);
executionContext.setStylesheetRoot(this);
setupFormatterListener(outputTarget, executionContext);
executionContext.setRootDocument(sourceTree);
#if defined(XALAN_RECURSIVE_STYLESHEET_EXECUTION)
typedef StylesheetExecutionContext::PushAndPopContextMarker PushAndPopContextMarker;
typedef StylesheetExecutionContext::PushAndPopElementFrame PushAndPopElementFrame;
typedef StylesheetExecutionContext::ResolveAndClearTopLevelParams ResolveAndClearTopLevelParams;
PushAndPopContextMarker thePushAndPopContextMarker(executionContext);
PushAndPopElementFrame thePushAndPopElementFrame(
executionContext,
0);
ResolveAndClearTopLevelParams theResolveAndClearTopLevelParams(executionContext);
#else
executionContext.pushContextMarker();
executionContext.pushElementFrame(0);
executionContext.resolveTopLevelParams();
#endif
#if defined(XALAN_VQ_SPECIAL_TRACE)
QuantifyStartRecordingData();
#endif
executionContext.startDocument();
executionContext.pushCurrentMode(&s_emptyQName);
const XPathExecutionContext::CurrentNodePushAndPop theCurrentNodePushAndPop(executionContext, sourceTree);
// Output the action of the found root rule. All processing
// occurs from here.
rootRule->execute(executionContext);
// At this point, anything transient during the tranformation
// may have been deleted, so we may not refer to anything the
// execution context may have created for us.
executionContext.endDocument();
#if defined(XALAN_VQ_SPECIAL_TRACE)
QuantifyStopRecordingData();
#endif
#if !defined(XALAN_RECURSIVE_STYLESHEET_EXECUTION)
executionContext.clearTopLevelParams();
executionContext.popElementFrame();
executionContext.popContextMarker();
#endif
}
const XalanDOMString&
StylesheetRoot::getEncoding(const XSLTResultTarget& outputTarget) const
{
const XalanDOMString& theEncoding = outputTarget.getEncoding();
if (theEncoding.length() != 0)
{
return theEncoding;
}
else
{
return m_encoding;
}
}
FormatterListener*
StylesheetRoot::setupFormatterListener(
XSLTResultTarget& outputTarget,
StylesheetExecutionContext& executionContext) const
{
typedef StylesheetExecutionContext::GetCachedString GetCachedString;
FormatterListener* flistener = outputTarget.getFormatterListener();
if (flistener != 0)
{
// Do encoding stuff here...
}
else if (0 != outputTarget.getCharacterStream() ||
0 != outputTarget.getByteStream() ||
0 != outputTarget.getStream() ||
!outputTarget.getFileName().empty())
{
/*
* Output target has a character or byte stream or file
*/
Writer* pw = 0;
if (0 != outputTarget.getCharacterStream())
{
pw = outputTarget.getCharacterStream();
}
else
{
if (0 != outputTarget.getByteStream())
{
pw = executionContext.createPrintWriter(*outputTarget.getByteStream());
}
else if (0 != outputTarget.getStream())
{
pw = executionContext.createPrintWriter(outputTarget.getStream());
}
else if (!outputTarget.getFileName().empty())
{
const GetCachedString theGuard(executionContext);
pw = executionContext.createPrintWriter(
outputTarget.getFileName(),
theGuard.get());
}
else
{
const GetCachedString theGuard(executionContext);
executionContext.problem(
StylesheetExecutionContext::eXSLTProcessor,
StylesheetExecutionContext::eError,
XalanMessageLoader::getMessage(
theGuard.get(),
XalanMessages::NoValidResultTarget),
0,
executionContext.getCurrentNode());
}
}
int indentAmount = executionContext.getIndent();
// If the indent amount is less than 0, that means use
// the value specified in the stylesheet.
if (indentAmount < 0)
{
indentAmount = m_indentAmount;
}
const bool doIndent = (indentAmount > -1) ? true : getOutputIndent();
const XalanDOMString& theEncoding = getEncoding(outputTarget);
switch(m_outputMethod)
{
case FormatterListener::OUTPUT_METHOD_HTML:
{
if (doIndent == true && indentAmount < 0)
{
indentAmount = FormatterToHTML::eDefaultIndentAmount;
}
// Start with the default that was set in the stylesheet...
bool outputEscapeURLs = m_outputEscapeURLs;
{
const StylesheetExecutionContext::eEscapeURLs eEscapeURLs =
executionContext.getEscapeURLs();
// If it's anything other than StylesheetExecutionContext::eEscapeURLsDefault,
// use the property from the execution context...
if (eEscapeURLs == StylesheetExecutionContext::eEscapeURLsNo)
{
outputEscapeURLs = false;
}
else if (eEscapeURLs == StylesheetExecutionContext::eEscapeURLsYes)
{
outputEscapeURLs = true;
}
}
// Start with the default that was set in the stylesheet...
bool omitMETATag = m_omitMETATag;
{
const StylesheetExecutionContext::eOmitMETATag eOmitMETATag =
executionContext.getOmitMETATag();
// If it's anything other than StylesheetExecutionContext::eOmitMETATagDefault,
// use the property from the execution context...
if (eOmitMETATag == StylesheetExecutionContext::eOmitMETATagNo)
{
omitMETATag = false;
}
else if (eOmitMETATag == StylesheetExecutionContext::eOmitMETATagYes)
{
omitMETATag = true;
}
}
flistener = executionContext.createFormatterToHTML(
*pw,
theEncoding,
m_mediatype,
m_doctypeSystem,
m_doctypePublic,
doIndent,
indentAmount,
outputEscapeURLs,
omitMETATag);
}
break;
case FormatterListener::OUTPUT_METHOD_TEXT:
flistener = executionContext.createFormatterToText(*pw, theEncoding);
break;
case FormatterListener::OUTPUT_METHOD_NONE:
case FormatterListener::OUTPUT_METHOD_XML:
default:
// Make sure we don't have a negative indent amount if we're
// indenting
if (doIndent == true && indentAmount < 0)
{
indentAmount = FormatterToXML::eDefaultIndentAmount;
}
flistener = executionContext.createFormatterToXML(
*pw, m_version, doIndent, indentAmount, theEncoding, m_mediatype,
m_doctypeSystem, m_doctypePublic, !m_omitxmlDecl, m_standalone);
break;
}
executionContext.setFormatterListener(flistener);
}
else
{
const GetCachedString theGuard(executionContext);
executionContext.problem(
StylesheetExecutionContext::eXSLTProcessor,
StylesheetExecutionContext::eError,
XalanMessageLoader::getMessage(
theGuard.get(),
XalanMessages::NoValidResultTarget),
0,
executionContext.getCurrentNode());
}
executionContext.setFormatterListener(flistener);
return flistener;
}
void
StylesheetRoot::processOutputSpec(
const XalanDOMChar* name,
const AttributeListType& atts,
StylesheetConstructionContext& constructionContext)
{
const XalanSize_t nAttrs = atts.getLength();
const Locator* const theLocator = constructionContext.getLocatorFromStack();
for (XalanSize_t i = 0; i < nAttrs; i++)
{
const XalanDOMChar* const aname = atts.getName(i);
if (equals(aname, Constants::ATTRNAME_OUTPUT_METHOD))
{
const XalanDOMChar* const method = atts.getValue(i);
if (equals(method, Constants::ATTRVAL_OUTPUT_METHOD_HTML))
{
m_outputMethod = FormatterListener::OUTPUT_METHOD_HTML;
}
else if (equals(method, Constants::ATTRVAL_OUTPUT_METHOD_XML))
{
m_outputMethod = FormatterListener::OUTPUT_METHOD_XML;
}
else if (equals(method, Constants::ATTRVAL_OUTPUT_METHOD_TEXT))
{
m_outputMethod = FormatterListener::OUTPUT_METHOD_TEXT;
}
else
{
const StylesheetConstructionContext::GetCachedString theGuard(constructionContext);
constructionContext.problem(
StylesheetConstructionContext::eXSLTProcessor,
StylesheetConstructionContext::eWarning,
XalanMessageLoader::getMessage(
theGuard.get(),
XalanMessages::OutputHasAnUnknownMethod_1Param,
method),
theLocator,
0);
}
}
else if (equals(aname, Constants::ATTRNAME_OUTPUT_VERSION))
{
m_version = atts.getValue(i);
}
else if (equals(aname,Constants::ATTRNAME_OUTPUT_INDENT))
{
m_indentResult =
getYesOrNo(aname, atts.getValue(i), constructionContext) == true ?
eIndentYesExplicit :
eIndentNoExplicit;
}
else if (equals(aname,Constants::ATTRNAME_OUTPUT_ENCODING))
{
m_encoding = atts.getValue(i);
}
else if (equals(aname,Constants::ATTRNAME_OUTPUT_MEDIATYPE))
{
m_mediatype = atts.getValue(i);
}
else if (equals(aname,Constants::ATTRNAME_OUTPUT_DOCTYPE_SYSTEM))
{
m_doctypeSystem = atts.getValue(i);
}
else if (equals(aname,Constants::ATTRNAME_OUTPUT_DOCTYPE_PUBLIC))
{
m_doctypePublic = atts.getValue(i);
}
else if (equals(aname,Constants::ATTRNAME_OUTPUT_OMITXMLDECL))
{
m_omitxmlDecl = getYesOrNo(aname, atts.getValue(i), constructionContext);
}
else if (equals(aname,Constants::ATTRNAME_OUTPUT_STANDALONE))
{
m_standalone = atts.getValue(i);
}
else if (equals(aname,Constants::ATTRNAME_OUTPUT_CDATA_SECTION_ELEMENTS))
{
if (m_outputMethod == FormatterListener::OUTPUT_METHOD_NONE ||
m_outputMethod == FormatterListener::OUTPUT_METHOD_XML)
{
StringTokenizer theTokenizer(atts.getValue(i));
StringTokenizer::size_type theTokenCount =
theTokenizer.countTokens();
m_cdataSectionElems.reserve(m_cdataSectionElems.size() + theTokenCount);
const StylesheetConstructionContext::GetCachedString theGuard(constructionContext);
XalanDOMString& theToken = theGuard.get();
while (theTokenCount > 0)
{
theTokenizer.nextToken(theToken);
--theTokenCount;
m_cdataSectionElems.push_back(
constructionContext.createXalanQName(theToken, getNamespaces(), theLocator, true));
}
assert(theTokenizer.hasMoreTokens() == false);
}
}
else
{
const XalanQNameByValue theAttributeName(aname, getNamespaces(), constructionContext.getMemoryManager(), theLocator );
if (theAttributeName.getNamespace() == constructionContext.getXalanXSLNameSpaceURL())
{
if (theAttributeName.getLocalPart() == Constants::ATTRNAME_ESCAPE_URLS)
{
m_outputEscapeURLs = getYesOrNo(aname, atts.getValue(i), constructionContext);
}
else if (theAttributeName.getLocalPart() == Constants::ATTRNAME_INDENTAMOUNT)
{
m_indentAmount = WideStringToInt(atts.getValue(i));
if (m_indentAmount < 0)
{
m_indentAmount = 0;
}
}
else if (theAttributeName.getLocalPart() == Constants::ATTRNAME_OMIT_META_TAG)
{
m_omitMETATag = getYesOrNo(aname, atts.getValue(i), constructionContext);
}
else
{
const StylesheetConstructionContext::GetCachedString theGuard(constructionContext);
constructionContext.problem(
StylesheetConstructionContext::eXSLTProcessor,
StylesheetConstructionContext::eWarning,
XalanMessageLoader::getMessage(
theGuard.get(),
XalanMessages::UnsupportedXalanSpecificAttribute_1Param,
theAttributeName.getLocalPart()),
theLocator,
0);
}
}
else if (isAttrOK(aname, atts, i, constructionContext) == false)
{
const StylesheetConstructionContext::GetCachedString theGuard(constructionContext);
constructionContext.problem(
StylesheetConstructionContext::eXSLTProcessor,
StylesheetConstructionContext::eError,
XalanMessageLoader::getMessage(
theGuard.get(),
XalanMessages::HasIllegalAttribute_2Param,
name,
aname),
theLocator,
0);
}
}
}
// If HTML output
if (m_outputMethod == FormatterListener::OUTPUT_METHOD_HTML &&
m_indentResult == eIndentNoImplicit)
{
m_indentResult = eIndentYesImplicit;
}
}
void
StylesheetRoot::initDefaultRule(StylesheetConstructionContext& constructionContext)
{
if (m_defaultRule == 0)
{
assert(m_defaultTextRule == 0);
assert(m_defaultRootRule == 0);
AttributeListImpl attrs(constructionContext.getMemoryManager());
attrs.addAttribute(
Constants::ATTRNAME_MATCH.c_str(),
Constants::ATTRTYPE_CDATA.c_str(),
XPath::PSEUDONAME_ANY);
m_defaultRule =
constructionContext.createElement(
StylesheetConstructionContext::ELEMNAME_TEMPLATE,
*this,
attrs);
assert(m_defaultRule != 0);
attrs.clear();
ElemTemplateElement* childrenElement =
constructionContext.createElement(
StylesheetConstructionContext::ELEMNAME_APPLY_TEMPLATES,
*this,
attrs);
assert(childrenElement != 0);
m_defaultRule->appendChildElem(childrenElement);
m_defaultRule->setDefaultTemplate(true);
// -----------------------------
attrs.clear();
attrs.addAttribute(
Constants::ATTRNAME_MATCH.c_str(),
Constants::ATTRTYPE_CDATA.c_str(),
Constants::ATTRVAL_DEFAULT_TEXT_RULE.c_str());
m_defaultTextRule =
constructionContext.createElement(
StylesheetConstructionContext::ELEMNAME_TEMPLATE,
*this,
attrs);
assert(m_defaultTextRule != 0);
attrs.clear();
attrs.addAttribute(
Constants::ATTRNAME_SELECT.c_str(),
Constants::ATTRTYPE_CDATA.c_str(),
Constants::ATTRVAL_THIS.c_str());
childrenElement =
constructionContext.createElement(
StylesheetConstructionContext::ELEMNAME_VALUE_OF,
*this,
attrs);
assert(childrenElement != 0);
m_defaultTextRule->appendChildElem(childrenElement);
m_defaultTextRule->setDefaultTemplate(true);
//--------------------------------
attrs.clear();
attrs.addAttribute(
Constants::ATTRNAME_MATCH.c_str(),
Constants::ATTRTYPE_CDATA.c_str(),
XPath::PSEUDONAME_ROOT);
m_defaultRootRule =
constructionContext.createElement(
StylesheetConstructionContext::ELEMNAME_TEMPLATE,
*this,
attrs);
assert(m_defaultRootRule != 0);
attrs.clear();
childrenElement =
constructionContext.createElement(
StylesheetConstructionContext::ELEMNAME_APPLY_TEMPLATES,
*this,
attrs);
assert(childrenElement != 0);
m_defaultRootRule->appendChildElem(childrenElement);
m_defaultRootRule->setDefaultTemplate(true);
}
assert(m_defaultRule != 0);
assert(m_defaultTextRule != 0);
assert(m_defaultRootRule != 0);
}
bool
StylesheetRoot::isCDATASectionElementName(const XalanQName& theQName) const
{
using std::find_if;
return find_if(
m_cdataSectionElems.begin(),
m_cdataSectionElems.end(),
pointer_equals_predicate<XalanQName>(&theQName)) != m_cdataSectionElems.end() ? true : false;
}
inline XalanNode*
getKeyNode(XalanNode* context)
{
assert(context != 0);
XalanDocument* const docNode =
XalanNode::DOCUMENT_NODE == context->getNodeType() ?
static_cast<XalanDocument*>(context) :
context->getOwnerDocument();
assert(docNode != 0);
// This is a big hack for dealing with result tree fragments coerced to node-sets using the
// node-set extension function. For such cases, the "document" is really the
// XalanDocumentFragment instance that owns the nodes, not the owner document.
if (docNode->getFirstChild() != 0)
{
return docNode;
}
else
{
XalanNode* currentNode = context;
// OK, the current node belongs to the document, but the document
// is just a factory for fragments. This loop will find the
// parent document fragment.
for(;;)
{
if (currentNode->getNodeType() == XalanNode::DOCUMENT_FRAGMENT_NODE)
{
break;
}
else
{
currentNode = DOMServices::getParentOfNode(*currentNode);
assert(currentNode != 0);
}
}
return currentNode;
}
}
void
StylesheetRoot::getNodeSetByKey(
XalanNode* context,
const XalanQName& qname,
const XalanDOMString& ref,
const PrefixResolver& resolver,
MutableNodeRefList& nodelist,
StylesheetExecutionContext& executionContext,
const Locator* locator,
KeyTablesTableType& theKeysTable) const
{
assert(
nodelist.empty() == true ||
nodelist.getDocumentOrder() == true);
const MutableNodeRefList* nl = 0;
XalanNode* const theKeyNode = getKeyNode(context);
assert(theKeyNode != 0);
if (m_needToBuildKeysTable == true)
{
assert(m_keyDeclarations.empty() == false);
const KeyTablesTableType::const_iterator i =
theKeysTable.find(theKeyNode);
if (i != theKeysTable.end())
{
nl = i->second->getNodeSetByKey(qname, ref);
}
else
{
XalanMemMgrAutoPtr<KeyTable> kt(
executionContext.getMemoryManager(),
KeyTable::create(
executionContext.getMemoryManager(),
theKeyNode,
resolver,
m_keyDeclarations,
executionContext));
theKeysTable[theKeyNode] = kt.get();
const KeyTable* const theNewTable = kt.releasePtr();
nl = theNewTable->getNodeSetByKey(qname, ref);
}
}
if (nl == 0)
{
typedef StylesheetExecutionContext::GetCachedString GetCachedString;
const GetCachedString theGuard1(executionContext);
const GetCachedString theGuard2(executionContext);
executionContext.problem(
StylesheetExecutionContext::eXSLTProcessor,
StylesheetExecutionContext::eError,
XalanMessageLoader::getMessage(
theGuard1.get(),
XalanMessages::UnknownKey_1Param,
qname.format(theGuard2.get())),
locator,
executionContext.getCurrentNode());
}
else if (nodelist.empty() == true)
{
nodelist = *nl;
}
else
{
nodelist.addNodesInDocOrder(*nl, executionContext);
}
}
bool
StylesheetRoot::internalShouldStripSourceNode(const XalanText& textNode) const
{
assert(
textNode.isWhitespace() == true &&
hasPreserveOrStripSpaceElements() == true);
const XalanNode* const parent = textNode.getParentNode();
// assert(parent != 0);
// Constructed nodesets may not have parents - see xalan:nodeset()
if (parent == 0)
return false;
if (parent->getNodeType() == XalanNode::ELEMENT_NODE)
{
const XalanElement* const theElement =
static_cast<const XalanElement*>(parent);
typedef WhitespaceElementsVectorType::const_iterator const_iterator;
const_iterator i = m_whitespaceElements.begin();
do
{
const XalanSpaceNodeTester& theTester = *i;
if (theTester(*theElement) != XPath::eMatchScoreNone)
{
return theTester.getType() == XalanSpaceNodeTester::eStrip;
}
++i;
} while (i != m_whitespaceElements.end());
}
return false;
}
void
StylesheetRoot::addAttributeSet(ElemAttributeSet& theAttributeSet)
{
m_attributeSetsMap[&theAttributeSet.getQName()].push_back(&theAttributeSet);
}
#if !defined(XALAN_RECURSIVE_STYLESHEET_EXECUTION)
const ElemAttributeSet*
StylesheetRoot::getAttributeSet(
StylesheetExecutionContext& executionContext,
const XalanQName& theQName,
size_type matchingIndex,
const Locator* theLocator) const
{
const AttributeSetMapType::const_iterator i =
m_attributeSetsMap.find(&theQName);
if (i == m_attributeSetsMap.end())
{
const StylesheetExecutionContext::GetCachedString theGuard(executionContext);
executionContext.problem(
StylesheetExecutionContext::eXSLTProcessor,
StylesheetExecutionContext::eError,
XalanMessageLoader::getMessage(
theGuard.get(),
XalanMessages::UnknownNodeType_1Param,
Constants::ELEMNAME_ATTRIBUTESET_WITH_PREFIX_STRING),
theLocator,
executionContext.getCurrentNode());
}
else
{
const AttributeSetVectorType& theAttributeSets = i->second;
if (matchingIndex < theAttributeSets.size())
{
return theAttributeSets[matchingIndex];
}
}
return 0;
}
#else
void
StylesheetRoot::executeAttributeSet(
StylesheetExecutionContext& theExecutionContext,
const XalanQName& theQName,
const Locator* theLocator) const
{
const AttributeSetMapType::const_iterator i =
m_attributeSetsMap.find(&theQName);
if (i == m_attributeSetsMap.end())
{
const GetCachedString theGuard(theExecutionContext);
theExecutionContext.error(
XalanMessageLoader::getMessage(
theGuard.get(),
XalanMessages::UnknownNodeType_1Param,
Constants::ELEMNAME_ATTRIBUTESET_WITH_PREFIX_STRING),
theExecutionContext.getCurrentNode(),
theLocator);
}
else
{
const AttributeSetVectorType& theAttributeSets = (*i).second;
const AttributeSetVectorType::const_iterator theEnd = theAttributeSets.end();
for(AttributeSetVectorType::const_iterator i = theAttributeSets.begin(); i != theEnd; ++i)
{
assert(*i != 0);
(*i)->execute(theExecutionContext);
}
}
}
#endif
}