blob: 74dd4938ad4c0539d215f052aa1ce05fc007dfaf [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.
*/
#include "ElemLiteralResult.hpp"
#include <xercesc/sax/AttributeList.hpp>
#include <xalanc/PlatformSupport/DoubleSupport.hpp>
#include <xalanc/PlatformSupport/XalanMessageLoader.hpp>
#include <xalanc/DOMSupport/DOMServices.hpp>
#include "AVT.hpp"
#include "Constants.hpp"
#include "Stylesheet.hpp"
#include "StylesheetConstructionContext.hpp"
#include "StylesheetExecutionContext.hpp"
namespace XALAN_CPP_NAMESPACE {
ElemLiteralResult::ElemLiteralResult(
StylesheetConstructionContext& constructionContext,
Stylesheet& stylesheetTree,
const XalanDOMChar* name,
const AttributeListType& atts,
XalanFileLoc lineNumber,
XalanFileLoc columnNumber) :
ElemUse(
constructionContext,
stylesheetTree,
lineNumber,
columnNumber,
StylesheetConstructionContext::ELEMNAME_LITERAL_RESULT),
m_elementName(constructionContext.getPooledString(name)),
m_avts(0),
m_avtsCount(0)
{
init(constructionContext, stylesheetTree, name, atts);
}
ElemLiteralResult::ElemLiteralResult(
StylesheetConstructionContext& constructionContext,
Stylesheet& stylesheetTree,
const XalanDOMChar* name,
const AttributeListType& atts,
XalanFileLoc lineNumber,
XalanFileLoc columnNumber,
int xslToken) :
ElemUse(constructionContext,
stylesheetTree,
lineNumber,
columnNumber,
xslToken),
m_elementName(constructionContext.getPooledString(name)),
m_avts(0),
m_avtsCount(0)
{
init(constructionContext, stylesheetTree, name, atts);
}
void
ElemLiteralResult::init(
StylesheetConstructionContext& constructionContext,
Stylesheet& stylesheetTree,
const XalanDOMChar* name,
const AttributeListType& atts)
{
assert(name != 0);
hasPrefix(indexOf(name, XalanUnicode::charColon) < length(name) ? true : false);
const XalanSize_t nAttrs = atts.getLength();
// This over-allocates, but we probably won't waste that much space.
m_avts = constructionContext.allocateAVTPointerVector(nAttrs);
assert(m_avts != 0);
const StylesheetConstructionContext::GetCachedString theGuard(constructionContext);
XalanDOMString& theBuffer = theGuard.get();
for (XalanSize_t i = 0; i < nAttrs; i++)
{
const XalanDOMChar* const aname = atts.getName(i);
bool needToProcess = true;
const XalanDOMString::size_type indexOfNSSep = indexOf(aname, XalanUnicode::charColon);
const XalanDOMString::size_type len = length(aname);
if (indexOfNSSep < len)
{
substring(aname, theBuffer, 0, indexOfNSSep);
if (!equals(theBuffer, DOMServices::s_XMLNamespace))
{
const XalanDOMString* const ns =
getNamespaceForPrefixInternal(theBuffer);
if (ns == 0)
{
error(
constructionContext,
XalanMessages::PrefixIsNotDeclared_1Param,
theBuffer);
}
else if (equals(*ns, stylesheetTree.getXSLTNamespaceURI()))
{
theBuffer.assign(aname + indexOfNSSep + 1, len - (indexOfNSSep + 1));
if (processPrefixControl(constructionContext, stylesheetTree, theBuffer, atts.getValue(i)) == true)
{
needToProcess = false;
}
else if (equals(theBuffer, Constants::ATTRNAME_VERSION) == true)
{
const XalanDOMChar* const value = atts.getValue(i);
stylesheetTree.setXSLTVerDeclared(
DoubleSupport::toDouble(value, constructionContext.getMemoryManager()));
}
}
}
else
{
// don't process namespace decls
needToProcess = false;
}
}
if (needToProcess == true)
{
processSpaceAttr(
m_elementName.c_str(),
aname,
atts,
i,
constructionContext);
// Add xmlns attribute(except xmlns:xsl), xml:space, etc...
// Ignore anything with xsl:xxx
if (processUseAttributeSets(
constructionContext,
aname,
atts,
i) == false &&
isAttrOK(
aname,
atts,
i,
constructionContext) == true)
{
m_avts[m_avtsCount++] =
constructionContext.createAVT(getLocator(), aname, atts.getValue(i), *this);
}
}
}
}
ElemLiteralResult::~ElemLiteralResult()
{
}
const XalanDOMString&
ElemLiteralResult::getElementName() const
{
return m_elementName;
}
class AVTPrefixChecker : public NamespacesHandler::PrefixChecker
{
public:
AVTPrefixChecker(
const AVT** theAVTs,
XalanSize_t theAVTsCount) :
m_avts(theAVTs),
m_avtsCount(theAVTsCount)
{
}
virtual bool
isActive(const XalanDOMString& thePrefix) const
{
bool fActive = false;
for (XalanSize_t i = 0; i < m_avtsCount; ++i)
{
const AVT* const avt = m_avts[i];
const XalanDOMString& theName = avt->getName();
const XalanDOMString::size_type theColonIndex = indexOf(theName, XalanUnicode::charColon);
if (theColonIndex != theName.length())
{
if (thePrefix.length() == theColonIndex &&
startsWith(theName, thePrefix) == true)
{
fActive = true;
break;
}
}
}
return fActive;
}
private:
// Not implemented...
AVTPrefixChecker&
operator=(const AVTPrefixChecker&);
// Data members...
const AVT** const m_avts;
const XalanSize_t m_avtsCount;
};
void
ElemLiteralResult::postConstruction(
StylesheetConstructionContext& constructionContext,
const NamespacesHandler& theParentHandler)
{
if (m_avtsCount != 0 ||
getNamespacesHandler().getNamespaceDeclarationsCount() != 0)
{
canGenerateAttributes(true);
}
else
{
// OK, let's turn this off and see what our
// base classes say about it when we chain up...
canGenerateAttributes(false);
}
// OK, now we can chain-up...
ElemUse::postConstruction(constructionContext, theParentHandler);
// OK, now let's do some more checking to see if we'll
// generate attributes...
if (canGenerateAttributes() == false)
{
// If there are no children, we can't generate any attributes...
if (hasChildren() == true)
{
assert(getFirstChildElem() != 0);
// If there's a single text child, or the first child
// is another LRE, then we won't generate any attributes.
// Otherwise, we might...
if (hasSingleTextChild() == false &&
getFirstChildElem()->getXSLToken() != StylesheetConstructionContext::ELEMNAME_LITERAL_RESULT)
{
canGenerateAttributes(true);
}
}
}
}
void
ElemLiteralResult::namespacesPostConstruction(
StylesheetConstructionContext& constructionContext,
const NamespacesHandler& theParentHandler,
NamespacesHandler& theHandler)
{
const AVTPrefixChecker theChecker(m_avts, m_avtsCount);
theHandler.postConstruction(
constructionContext,
true,
getElementName(),
&theParentHandler,
&theChecker);
}
#if !defined(XALAN_RECURSIVE_STYLESHEET_EXECUTION)
const ElemTemplateElement*
ElemLiteralResult::startElement(StylesheetExecutionContext& executionContext) const
{
const XalanDOMString& theElementName = getElementName();
executionContext.startElement(theElementName.c_str());
ElemUse::startElement(executionContext);
const NamespacesHandler& theNamespacesHandler = getNamespacesHandler();
theNamespacesHandler.outputResultNamespaces(executionContext);
if (hasPrefix() == false)
{
// OK, let's check to make sure we don't have to change the default namespace...
const XalanDOMString* const theCurrentDefaultNamespace =
executionContext.getResultNamespaceForPrefix(s_emptyString);
if (theCurrentDefaultNamespace != 0)
{
const XalanDOMString* const theElementDefaultNamespace =
theNamespacesHandler.getNamespace(s_emptyString);
if (theElementDefaultNamespace == 0)
{
// There was no default namespace, so we have to turn the
// current one off.
executionContext.addResultAttribute(DOMServices::s_XMLNamespace, s_emptyString);
}
else if (equals(*theCurrentDefaultNamespace, *theElementDefaultNamespace) == false)
{
executionContext.addResultAttribute(DOMServices::s_XMLNamespace, *theElementDefaultNamespace);
}
}
}
return beginExecuteChildren(executionContext);
}
void
ElemLiteralResult::endElement(StylesheetExecutionContext& executionContext) const
{
endExecuteChildren(executionContext);
executionContext.endElement(getElementName().c_str());
ElemUse::endElement(executionContext);
}
void
ElemLiteralResult::evaluateAVTs(StylesheetExecutionContext& executionContext) const
{
if (m_avtsCount > 0)
{
const StylesheetExecutionContext::GetCachedString theGuard(executionContext);
XalanDOMString& theStringedValue = theGuard.get();
for(XalanSize_t i = 0; i < m_avtsCount; ++i)
{
const AVT* const avt = m_avts[i];
const XalanDOMString& theName = avt->getName();
avt->evaluate(theStringedValue, *this, executionContext);
executionContext.addResultAttribute(theName, theStringedValue);
theStringedValue.clear();
}
}
}
#endif
#if defined(XALAN_RECURSIVE_STYLESHEET_EXECUTION)
void
ElemLiteralResult::execute(StylesheetExecutionContext& executionContext) const
{
const XalanDOMString& theElementName = getElementName();
executionContext.startElement(theElementName.c_str());
ElemUse::execute(executionContext);
const NamespacesHandler& theNamespacesHandler = getNamespacesHandler();
theNamespacesHandler.outputResultNamespaces(executionContext);
if (hasPrefix() == false)
{
// OK, let's check to make sure we don't have to change the default namespace...
const XalanDOMString* const theCurrentDefaultNamespace =
executionContext.getResultNamespaceForPrefix(s_emptyString);
if (theCurrentDefaultNamespace != 0)
{
const XalanDOMString* const theElementDefaultNamespace =
theNamespacesHandler.getNamespace(s_emptyString);
if (theElementDefaultNamespace == 0)
{
// There was no default namespace, so we have to turn the
// current one off.
executionContext.addResultAttribute(DOMServices::s_XMLNamespace, s_emptyString);
}
else if (equals(*theCurrentDefaultNamespace, *theElementDefaultNamespace) == false)
{
executionContext.addResultAttribute(DOMServices::s_XMLNamespace, *theElementDefaultNamespace);
}
}
}
if(m_avtsCount > 0)
{
const StylesheetExecutionContext::GetCachedString theGuard(executionContext);
XalanDOMString& theStringedValue = theGuard.get();
for(XalanSize_t i = 0; i < m_avtsCount; ++i)
{
const AVT* const avt = m_avts[i];
const XalanDOMString& theName = avt->getName();
avt->evaluate(theStringedValue, *this, executionContext);
executionContext.addResultAttribute(theName, theStringedValue);
theStringedValue.clear();
}
}
executeChildren(executionContext);
executionContext.endElement(theElementName.c_str());
}
#endif
bool
ElemLiteralResult::isAttrOK(
const XalanDOMChar* attrName,
const AttributeListType& /* atts */,
XalanSize_t /* which */,
StylesheetConstructionContext& constructionContext) const
{
bool isAttrOK = equals(attrName, DOMServices::s_XMLNamespace) ||
startsWith(attrName, DOMServices::s_XMLNamespaceWithSeparator);
if (isAttrOK == false)
{
const XalanDOMString::size_type len = length(attrName);
const XalanDOMString::size_type indexOfNSSep = indexOf(attrName, XalanUnicode::charColon);
if (indexOfNSSep >= len)
{
// An empty namespace is OK.
isAttrOK = true;
}
else
{
const StylesheetConstructionContext::GetCachedString theGuard(constructionContext);
XalanDOMString& thePrefix = theGuard.get();
thePrefix.assign(attrName, indexOfNSSep);
const XalanDOMString* const ns = getStylesheet().getNamespaceForPrefixFromStack(thePrefix);
if (ns != 0 && equals(*ns, constructionContext.getXSLTNamespaceURI()) == false)
{
isAttrOK = true;
}
}
}
return isAttrOK;
}
}