blob: c555e6fcdb3dbb72efb537b1974878605de999e4 [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 "NamespacesHandler.hpp"
#include <xalanc/PlatformSupport/StringTokenizer.hpp>
#include <xalanc/PlatformSupport/XalanMessageLoader.hpp>
#include <xalanc/DOMSupport/DOMServices.hpp>
#include "AVT.hpp"
#include "Constants.hpp"
#include "StylesheetConstructionContext.hpp"
#include "StylesheetExecutionContext.hpp"
namespace XALAN_CPP_NAMESPACE {
template<class VectorType, class MemberFunctionType>
const typename VectorType::value_type*
find(
const VectorType& theVector,
const XalanDOMString& theString,
MemberFunctionType theMemberFunction)
{
const typename VectorType::const_iterator theEnd(theVector.end());
typename VectorType::const_iterator theCurrent(theVector.begin());
while(theCurrent != theEnd)
{
if (((*theCurrent).*theMemberFunction)() == theString)
{
return &*theCurrent;
}
else
{
++theCurrent;
}
}
return 0;
}
template<class VectorType, class MemberFunctionType>
typename VectorType::value_type*
findNonConst(
VectorType& theVector,
const XalanDOMString& theString,
MemberFunctionType theMemberFunction)
{
const typename VectorType::iterator theEnd(theVector.end());
typename VectorType::iterator theCurrent(theVector.begin());
while(theCurrent != theEnd)
{
if (((*theCurrent).*theMemberFunction)() == theString)
{
return &*theCurrent;
}
else
{
++theCurrent;
}
}
return 0;
}
template<class VectorType>
const typename VectorType::value_type*
findByPrefix(
const VectorType& theVector,
const XalanDOMString& thePrefix)
{
typedef typename VectorType::value_type value_type;
return find(theVector, thePrefix, &value_type::getPrefix);
}
template<class VectorType>
typename VectorType::value_type*
findByPrefixNonConst(
VectorType& theVector,
const XalanDOMString& thePrefix)
{
typedef typename VectorType::value_type value_type;
return findNonConst(theVector, thePrefix, &value_type::getPrefix);
}
template<class VectorType>
const typename VectorType::value_type*
findByURI(
const VectorType& theVector,
const XalanDOMString& theNamespaceURI)
{
typedef typename VectorType::value_type value_type;
return find(theVector, theNamespaceURI, &value_type::getURI);
}
template<class VectorType>
bool
addByPrefix(
StylesheetConstructionContext& theConstructionContext,
VectorType& theVector,
const XalanDOMString& thePrefix,
const XalanDOMString& theURI)
{
typedef typename VectorType::value_type value_type;
const value_type* const theEntry =
findByPrefix(theVector, thePrefix);
if (theEntry != 0)
{
return false;
}
else
{
theVector.push_back(
value_type(
theConstructionContext.getPooledString(thePrefix),
theConstructionContext.getPooledString(theURI)));
return true;
}
}
template<class VectorType>
bool
addOrUpdateByPrefix(
StylesheetConstructionContext& theConstructionContext,
VectorType& theVector,
const XalanDOMString& thePrefix,
const XalanDOMString& theURI)
{
typedef typename VectorType::value_type value_type;
value_type* const theEntry =
findByPrefixNonConst(theVector, thePrefix);
if (theEntry == 0)
{
theVector.push_back(
value_type(
theConstructionContext.getPooledString(thePrefix),
theConstructionContext.getPooledString(theURI)));
return true;
}
else
{
if (theEntry->getURI() == theURI)
{
return false;
}
else
{
theEntry->setURI(theConstructionContext.getPooledString(theURI));
return true;
}
}
}
template<class VectorType>
const XalanDOMString*
findNamespace(
const VectorType& theVector,
const XalanDOMString& thePrefix)
{
typedef typename VectorType::value_type value_type;
const value_type* const theEntry =
findByPrefix(theVector, thePrefix);
if (theEntry == 0)
{
return 0;
}
else
{
return &theEntry->getURI();
}
}
const XalanDOMString NamespacesHandler::Namespace::s_emptyString(XalanMemMgrs::getDummyMemMgr());
NamespacesHandler::PrefixChecker::PrefixChecker()
{
}
NamespacesHandler::PrefixChecker::~PrefixChecker()
{
}
NamespacesHandler::NamespacesHandler(MemoryManager& theManager) :
m_excludedResultPrefixes(theManager),
m_namespaceDeclarations(theManager),
m_extensionNamespaceURIs(theManager),
m_namespaceAliases(theManager)
{
}
NamespacesHandler::NamespacesHandler(
StylesheetConstructionContext& theConstructionContext,
const NamespacesHandler& /* stylesheetNamespacesHandler */,
const NamespacesStackType& theCurrentNamespaces,
const XalanDOMString& theXSLTNamespaceURI) :
m_excludedResultPrefixes(theConstructionContext.getMemoryManager()),
m_namespaceDeclarations(theConstructionContext.getMemoryManager()),
m_extensionNamespaceURIs(theConstructionContext.getMemoryManager()),
m_namespaceAliases(theConstructionContext.getMemoryManager())
{
// Go through the namespaces stack in reverse order...
const NamespacesStackType::const_reverse_iterator theEnd =
theCurrentNamespaces.rend();
NamespacesStackType::const_reverse_iterator i =
theCurrentNamespaces.rbegin();
for(; i != theEnd; ++i)
{
// Process each namespace in the current vector...
const NamespaceVectorType::const_iterator theVectorEnd =
(*i).end();
NamespaceVectorType::const_iterator j =
(*i).begin();
for(; j != theVectorEnd; ++j)
{
const NameSpace& theNamespace = *j;
const XalanDOMString& theURI = theNamespace.getURI();
const XalanDOMString& thePrefix = theNamespace.getPrefix();
if(shouldExcludeResultNamespaceNode(
theXSLTNamespaceURI,
theURI) == false)
{
addByPrefix(
theConstructionContext,
m_namespaceDeclarations,
thePrefix,
theURI);
}
else
{
addByPrefix(
theConstructionContext,
m_excludedResultPrefixes,
thePrefix,
theURI);
assert(findByPrefix(m_excludedResultPrefixes, thePrefix) != 0 &&
findByPrefix(m_excludedResultPrefixes, thePrefix)->getURI() == theURI);
}
}
}
}
NamespacesHandler::~NamespacesHandler()
{
}
void
NamespacesHandler::addExtensionNamespaceURI(
StylesheetConstructionContext& theConstructionContext,
const XalanDOMString& theURI)
{
m_extensionNamespaceURIs.push_back(&theConstructionContext.getPooledString(theURI));
}
const XalanDOMString*
NamespacesHandler::getNamespace(const XalanDOMString& thePrefix) const
{
const NamespacesVectorType::value_type* theNamespace =
findByPrefix(m_excludedResultPrefixes, thePrefix);
if (theNamespace != 0)
{
return &theNamespace->getURI();
}
else
{
return findNamespace(m_namespaceDeclarations, thePrefix);
}
}
void
NamespacesHandler::copyNamespaceAliases(const NamespacesHandler& parentNamespacesHandler)
{
copyNamespaceAliases(parentNamespacesHandler.m_namespaceAliases);
}
const XalanDOMString*
NamespacesHandler::getNamespaceAlias(const XalanDOMString& theStylesheetNamespace) const
{
if (m_namespaceAliases.empty() == true)
{
return 0;
}
else
{
const NamespaceAliasesMapType::const_iterator i =
m_namespaceAliases.find(&theStylesheetNamespace);
if (i != m_namespaceAliases.end())
{
return (*i).second;
}
else
{
return 0;
}
}
}
void
NamespacesHandler::setNamespaceAlias(
StylesheetConstructionContext& theConstructionContext,
const XalanDOMString& theStylesheetNamespace,
const XalanDOMString& theResultNamespace)
{
m_namespaceAliases[&theConstructionContext.getPooledString(theStylesheetNamespace)] =
&theConstructionContext.getPooledString(theResultNamespace);
}
typedef StylesheetConstructionContext::GetCachedString GetCachedString;
void
NamespacesHandler::processExcludeResultPrefixes(
StylesheetConstructionContext& theConstructionContext,
const XalanDOMChar* theValue,
const NamespacesStackType& theCurrentNamespaces)
{
StringTokenizer tokenizer(
theValue,
Constants::DEFAULT_WHITESPACE_SEPARATOR_STRING);
const GetCachedString theGuard(theConstructionContext);
XalanDOMString& thePrefix = theGuard.get();
while(tokenizer.hasMoreTokens() == true)
{
tokenizer.nextToken(thePrefix);
if(equalsIgnoreCaseASCII(thePrefix, Constants::ATTRVAL_DEFAULT_PREFIX) == true)
{
thePrefix.clear();
}
const XalanDOMString* const theNamespaceURI =
XalanQName::getNamespaceForPrefix(theCurrentNamespaces, thePrefix);
if(theNamespaceURI == 0)
{
const GetCachedString theGuard(theConstructionContext);
theConstructionContext.problem(
StylesheetConstructionContext::eXSLTProcessor,
StylesheetConstructionContext::eError,
XalanMessageLoader::getMessage(
theGuard.get(),
XalanMessages::PrefixIsNotDeclared_1Param,
thePrefix),
theConstructionContext.getLocatorFromStack(),
0);
}
addOrUpdateByPrefix(
theConstructionContext,
m_excludedResultPrefixes,
thePrefix,
*theNamespaceURI);
assert(findByPrefix(m_excludedResultPrefixes, thePrefix) != 0 &&
findByPrefix(m_excludedResultPrefixes, thePrefix)->getURI() == *theNamespaceURI);
}
}
void
NamespacesHandler::processExtensionElementPrefixes(
StylesheetConstructionContext& theConstructionContext,
const XalanDOMChar* theValue,
const NamespacesStackType& theCurrentNamespaces)
{
StringTokenizer tokenizer(
theValue,
Constants::DEFAULT_WHITESPACE_SEPARATOR_STRING);
const GetCachedString theGuard(theConstructionContext);
XalanDOMString& thePrefix = theGuard.get();
while(tokenizer.hasMoreTokens() == true)
{
tokenizer.nextToken(thePrefix);
if(equalsIgnoreCaseASCII(thePrefix, Constants::ATTRVAL_DEFAULT_PREFIX) == true)
{
thePrefix.clear();
}
const XalanDOMString* const theNamespace =
XalanQName::getNamespaceForPrefix(theCurrentNamespaces, thePrefix);
if(theNamespace == 0)
{
const GetCachedString theGuard(theConstructionContext);
theConstructionContext.problem(
StylesheetConstructionContext::eXSLTProcessor,
StylesheetConstructionContext::eError,
XalanMessageLoader::getMessage(
theGuard.get(),
XalanMessages::PrefixIsNotDeclared_1Param,
thePrefix),
theConstructionContext.getLocatorFromStack(),
0);
}
assert(theNamespace != 0);
m_extensionNamespaceURIs.push_back(&theConstructionContext.getPooledString(*theNamespace));
}
}
void
NamespacesHandler::postConstruction(
StylesheetConstructionContext& theConstructionContext,
bool fProcessNamespaceAliases,
const XalanDOMString& theElementName,
const NamespacesHandler* parentNamespacesHandler,
const PrefixChecker* prefixChecker)
{
// Copy everything from the parent handler, if there is one...
if (parentNamespacesHandler != 0)
{
copyNamespaceAliases(parentNamespacesHandler->m_namespaceAliases);
copyExtensionNamespaceURIs(parentNamespacesHandler->m_extensionNamespaceURIs);
copyExcludeResultPrefixes(parentNamespacesHandler->m_excludedResultPrefixes);
}
// Figure out the prefix of the owning element, to make sure we
// don't exclude its prefix.
const XalanDOMString::size_type indexOfNSSep = indexOf(theElementName, XalanUnicode::charColon);
const GetCachedString theGuard(theConstructionContext);
XalanDOMString& thePrefix = theGuard.get();
if (indexOfNSSep < theElementName.length())
{
substring(theElementName, thePrefix, 0, indexOfNSSep);
}
processExcludeResultPrefixes(theConstructionContext, thePrefix, prefixChecker);
if (fProcessNamespaceAliases == true)
{
// $$ ToDo: Does this happen before or after exclude-result-prefixes?
processNamespaceAliases();
}
createResultAttributeNames(theConstructionContext);
}
NamespacesHandler&
NamespacesHandler::operator=(const NamespacesHandler& theRHS)
{
if (&theRHS != this)
{
m_excludedResultPrefixes = theRHS.m_excludedResultPrefixes;
m_namespaceDeclarations = theRHS.m_namespaceDeclarations;
m_extensionNamespaceURIs = theRHS.m_extensionNamespaceURIs;
m_namespaceAliases = theRHS.m_namespaceAliases;
}
return *this;
}
bool
NamespacesHandler::shouldExcludeResultNamespaceNode(
const XalanDOMString& theXSLTNamespaceURI,
const XalanDOMString& theURI) const
{
// These are commone namespaces that are always excluded...
if(equals(theURI, theXSLTNamespaceURI)
|| isExtensionNamespaceURI(theURI) == true
|| equals(theURI, DOMServices::s_XMLNamespaceURI))
{
return true;
}
else if (isExcludedNamespaceURI(theURI) == true)
{
// It was found in the excluded result prefixes URIs...
return true;
}
else
{
return false;
}
}
void
NamespacesHandler::outputResultNamespaces(
StylesheetExecutionContext& theExecutionContext,
bool supressDefault) const
{
// Write out the namespace declarations...
if (m_namespaceDeclarations.empty() == false)
{
const NamespaceExtendedVectorType::const_iterator theEnd =
m_namespaceDeclarations.end();
NamespaceExtendedVectorType::const_iterator i =
m_namespaceDeclarations.begin();
for(; i != theEnd; ++i)
{
const NamespaceExtended& theNamespace = *i;
const XalanDOMString& thePrefix = theNamespace.getPrefix();
// If we're not supposed to suppress the default namespace, or
// there's a prefix (so it's not the default), we can continue
// to see if we need to add the result namespace.
if (supressDefault == false ||
thePrefix.empty() == false)
{
const XalanDOMString& theResultURI = theNamespace.getURI();
assert(theNamespace.getResultAttributeName().empty() == false);
// Get the any namespace declaration currently active for the
// prefix.
const XalanDOMString* const desturi =
theExecutionContext.getResultNamespaceForPrefix(thePrefix);
// Is there already an active namespace declaration?
if(desturi == 0 || !equals(theResultURI, *desturi))
{
// No, so add one...
theExecutionContext.addResultAttribute(theNamespace.getResultAttributeName(), theResultURI);
}
}
}
}
}
bool
NamespacesHandler::isExcludedNamespaceURI(const XalanDOMString& theNamespaceURI) const
{
return findByURI(m_excludedResultPrefixes, theNamespaceURI) != 0 ? true : false;
}
bool
NamespacesHandler::findString(
const XalanDOMString& theString,
const XalanDOMStringPointerVectorType& theVector)
{
const XalanDOMStringPointerVectorType::const_iterator theEnd = theVector.end();
XalanDOMStringPointerVectorType::const_iterator theCurrent = theVector.begin();
while(theCurrent != theEnd)
{
assert(*theCurrent != 0);
const XalanDOMString* const theCurrentString = *theCurrent;
if (theString == *theCurrentString)
{
return true;
}
++theCurrent;
}
return false;
}
void
NamespacesHandler::clear()
{
m_excludedResultPrefixes.clear();
m_namespaceDeclarations.clear();
m_extensionNamespaceURIs.clear();
m_namespaceAliases.clear();
}
void
NamespacesHandler::swap(NamespacesHandler& theOther)
{
m_excludedResultPrefixes.swap(theOther.m_excludedResultPrefixes);
m_namespaceDeclarations.swap(theOther.m_namespaceDeclarations);
m_extensionNamespaceURIs.swap(theOther.m_extensionNamespaceURIs);
m_namespaceAliases.swap(theOther.m_namespaceAliases);
}
void
NamespacesHandler::createResultAttributeNames(StylesheetConstructionContext& theConstructionContext)
{
// Go through all of the result namespaces and create the attribute
// name that will be used when they're written to the result tree.
// This is more efficient if the stylesheet is used multiple times.
if (m_namespaceDeclarations.empty() == false)
{
const NamespaceExtendedVectorType::iterator theEnd =
m_namespaceDeclarations.end();
NamespaceExtendedVectorType::iterator i =
m_namespaceDeclarations.begin();
const GetCachedString theGuard(theConstructionContext);
XalanDOMString& theName = theGuard.get();
for(; i != theEnd; ++i)
{
NamespaceExtended& theNamespace = *i;
const XalanDOMString& thePrefix = theNamespace.getPrefix();
if (thePrefix.empty() == false)
{
// Create a name of the form xmlns:prefix, where "prefix" is the
// text of the prefix.
// Reserve the appropriate amount of space in the string.
theName.reserve(DOMServices::s_XMLNamespaceWithSeparatorLength + thePrefix.length() + 1);
theName = DOMServices::s_XMLNamespaceWithSeparator;
theName += thePrefix;
theNamespace.setResultAttributeName(theConstructionContext.getPooledString(theName));
}
else
{
// It's the default namespace...
theNamespace.setResultAttributeName(DOMServices::s_XMLNamespace);
}
}
}
}
void
NamespacesHandler::processExcludeResultPrefixes(
StylesheetConstructionContext& theConstructionContext,
const XalanDOMString& theElementPrefix,
const PrefixChecker* prefixChecker)
{
if (m_excludedResultPrefixes.empty() == false)
{
NamespaceExtendedVectorType::iterator i =
m_namespaceDeclarations.begin();
// Check for any result prefixes we should exclude...
while(i != m_namespaceDeclarations.end())
{
const Namespace& theNamespace = *i;
const XalanDOMString& thePrefix = theNamespace.getPrefix();
const XalanDOMString& theURI = theNamespace.getURI();
// We can never exclude the prefix of our owner element, so
// check that first...
if (equals(thePrefix, theElementPrefix) == false &&
(prefixChecker == 0 || prefixChecker->isActive(thePrefix) == false) &&
(isExcludedNamespaceURI(theURI) == true ||
isExtensionNamespaceURI(theURI) == true))
{
// Add it to the excluded prefixes, in case we need it later...
m_excludedResultPrefixes.push_back(
NamespacesVectorType::value_type(
theConstructionContext.getPooledString(thePrefix),
theConstructionContext.getPooledString(theURI)));
// It's excluded, so remove it...
i = m_namespaceDeclarations.erase(i);
}
else
{
++i;
}
}
}
}
void
NamespacesHandler::processNamespaceAliases()
{
if (m_namespaceDeclarations.empty() == false)
{
const NamespaceExtendedVectorType::iterator theEnd =
m_namespaceDeclarations.end();
NamespaceExtendedVectorType::iterator i =
m_namespaceDeclarations.begin();
// Look at everyone of my namespaces for an alias, and substitute the
// alias as appropriate...
for(; i != theEnd; ++i)
{
Namespace& theNamespace = *i;
const XalanDOMString& theURI =
theNamespace.getURI();
const XalanDOMString* const theAlias =
getNamespaceAlias(theURI);
// Is there a local alias?
if (theAlias != 0)
{
// Yup, so use it...
theNamespace.setURI(*theAlias);
}
}
}
}
void
NamespacesHandler::copyNamespaceAliases(const NamespaceAliasesMapType& theNamespaceAliases)
{
if (theNamespaceAliases.empty() == false)
{
if (m_namespaceAliases.empty() == true)
{
m_namespaceAliases = theNamespaceAliases;
}
else
{
const NamespaceAliasesMapType::const_iterator theEnd =
theNamespaceAliases.end();
NamespaceAliasesMapType::const_iterator i =
theNamespaceAliases.begin();
// Add them in...
while(i != theEnd)
{
m_namespaceAliases.insert(*i);
++i;
}
}
}
}
void
NamespacesHandler::copyExtensionNamespaceURIs(const XalanDOMStringPointerVectorType& theExtensionNamespaceURIs)
{
if (theExtensionNamespaceURIs.empty() == false)
{
if (m_extensionNamespaceURIs.empty() == true)
{
m_extensionNamespaceURIs = theExtensionNamespaceURIs;
}
else
{
const XalanDOMStringPointerVectorType::const_iterator theEnd =
theExtensionNamespaceURIs.end();
XalanDOMStringPointerVectorType::const_iterator i =
theExtensionNamespaceURIs.begin();
// Add them in...
while(i != theEnd)
{
assert(*i != 0);
if (isExtensionNamespaceURI(**i) == false)
{
m_extensionNamespaceURIs.push_back(*i);
}
++i;
}
}
}
}
void
NamespacesHandler::copyExcludeResultPrefixes(const NamespacesVectorType& theExcludeResultPrefixes)
{
if (theExcludeResultPrefixes.empty() == false)
{
if (m_excludedResultPrefixes.empty() == true)
{
m_excludedResultPrefixes = theExcludeResultPrefixes;
}
else
{
const NamespacesVectorType::const_iterator theEnd =
theExcludeResultPrefixes.end();
NamespacesVectorType::const_iterator i =
theExcludeResultPrefixes.begin();
// Add them in...
while(i != theEnd)
{
if (findByPrefix(m_excludedResultPrefixes, (*i).getPrefix()) == 0)
{
m_excludedResultPrefixes.push_back(*i);
}
++i;
}
}
}
}
}