blob: 6c2f0171b6ff9aaf8cc033c6646154987afb97ef [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.ibm.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
#include "ElemLiteralResult.hpp"
#include <algorithm>
#include <xercesc/sax/AttributeList.hpp>
#include <xercesc/sax/SAXException.hpp>
#include <Include/STLHelper.hpp>
#include <PlatformSupport/DoubleSupport.hpp>
#include <DOMSupport/DOMServices.hpp>
#include "AVT.hpp"
#include "Constants.hpp"
#include "Stylesheet.hpp"
#include "StylesheetConstructionContext.hpp"
#include "StylesheetExecutionContext.hpp"
ElemLiteralResult::ElemLiteralResult(
StylesheetConstructionContext& constructionContext,
Stylesheet& stylesheetTree,
const XalanDOMChar* name,
const AttributeList& atts,
int lineNumber,
int columnNumber,
int xslToken) :
ElemUse(constructionContext,
stylesheetTree,
lineNumber,
columnNumber,
xslToken),
m_elementName(name),
m_avts()
{
const unsigned int nAttrs = atts.getLength();
m_avts.reserve(nAttrs);
XalanDOMString theBuffer;
for(unsigned int 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)
{
constructionContext.error(
"Cannot resolve namespace prefix",
0,
this);
}
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));
}
}
}
else
{
// don't process namespace decls
needToProcess = false;
}
}
if(needToProcess == true)
{
processSpaceAttr(aname, atts, i, constructionContext);
// Add xmlns attribute(except xmlns:xsl), xml:space, etc...
// Ignore anything with xsl:xxx
if(! processUseAttributeSets(constructionContext, aname, atts, i) &&
isAttrOK(aname, atts, i, constructionContext))
{
m_avts.push_back(new AVT(getLocator(), aname, atts.getType(i), atts.getValue(i),
*this, constructionContext));
}
}
}
// Shrink the vector of AVTS, if necessary...
if (m_avts.capacity() > m_avts.size())
{
// Make a copy that's the exact size, and
// swap the two...
AVTVectorType(m_avts).swap(m_avts);
}
}
ElemLiteralResult::~ElemLiteralResult()
{
#if !defined(XALAN_NO_NAMESPACES)
using std::for_each;
#endif
// Clean up all entries in the vector.
for_each(m_avts.begin(),
m_avts.end(),
DeleteFunctor<AVT>());
}
const XalanDOMString&
ElemLiteralResult::getElementName() const
{
return m_elementName;
}
void
ElemLiteralResult::postConstruction(
StylesheetConstructionContext& constructionContext,
const NamespacesHandler& theParentHandler)
{
// OK, now check all attribute AVTs to make sure
// our NamespacesHandler knows about any prefixes
// that will need namespace declarations...
const AVTVectorType::size_type nAttrs = m_avts.size();
for(AVTVectorType::size_type i = 0; i < nAttrs; ++i)
{
const AVT* const avt = m_avts[i];
const XalanDOMString& theName = avt->getName();
const XalanDOMString::size_type theColonIndex = indexOf(theName, XalanUnicode::charColon);
if (theColonIndex != length(theName))
{
m_namespacesHandler.addActivePrefix(XalanDOMString(theName, 0, theColonIndex));
}
}
if (nAttrs != 0 ||
m_namespacesHandler.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() != Constants::ELEMNAME_LITERALRESULT)
{
canGenerateAttributes(true);
}
}
}
}
inline void
ElemLiteralResult::doAddResultAttribute(
StylesheetExecutionContext& executionContext,
const XalanDOMString& thePrefix,
const XalanDOMString& theName,
const XalanDOMString& theValue) const
{
if (isEmpty(thePrefix) == true ||
shouldExcludeResultNamespaceNode(
theValue) == false)
{
executionContext.addResultAttribute(
theName,
theValue);
}
}
void
ElemLiteralResult::execute(StylesheetExecutionContext& executionContext) const
{
const XalanDOMString& theElementName = getElementName();
executionContext.startElement(c_wstr(theElementName));
ElemUse::execute(executionContext);
m_namespacesHandler.outputResultNamespaces(executionContext);
// 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 =
m_namespacesHandler.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(0 != m_avts.size())
{
const AVTVectorType::size_type nAttrs = m_avts.size();
StylesheetExecutionContext::GetAndReleaseCachedString theGuard(executionContext);
XalanDOMString& theStringedValue = theGuard.get();
for(AVTVectorType::size_type i = 0; i < nAttrs; ++i)
{
const AVT* const avt = m_avts[i];
const XalanDOMString& theName = avt->getName();
const XalanDOMString& thePrefix = avt->getPrefix();
const XalanDOMString& theSimpleValue = avt->getSimpleValue();
if (isEmpty(theSimpleValue) == false)
{
doAddResultAttribute(executionContext, thePrefix, theName, theSimpleValue);
}
else
{
avt->evaluate(theStringedValue, executionContext.getCurrentNode(), *this, executionContext);
doAddResultAttribute(executionContext, thePrefix, theName, theStringedValue);
}
}
}
executeChildren(executionContext);
executionContext.endElement(c_wstr(theElementName));
}
bool
ElemLiteralResult::isAttrOK(
int tok,
const XalanDOMChar* attrName,
const AttributeList& atts,
int which) const
{
return ElemUse::isAttrOK(tok, attrName, atts, which);
}
bool
ElemLiteralResult::isAttrOK(
const XalanDOMChar* attrName,
const AttributeList& /* atts */,
int /* which */,
StylesheetConstructionContext& constructionContext) const
{
bool isAttrOK = equals(attrName, DOMServices::s_XMLNamespace) ||
startsWith(attrName, DOMServices::s_XMLNamespaceWithSeparator);
if(isAttrOK == false)
{
const XalanDOMString::size_type indexOfNSSep = indexOf(attrName, XalanUnicode::charColon);
if(indexOfNSSep < length(attrName))
{
const XalanDOMString prefix(attrName, indexOfNSSep);
const XalanDOMString* const ns = getStylesheet().getNamespaceForPrefixFromStack(prefix);
if (ns != 0 && equals(*ns, constructionContext.getXSLTNamespaceURI()) == false)
{
isAttrOK = true;
}
}
else
{
// An empty namespace is OK.
isAttrOK = true;
}
}
return isAttrOK;
}
bool
ElemLiteralResult::processPrefixControl(
StylesheetConstructionContext& constructionContext,
const Stylesheet& stylesheetTree,
const XalanDOMString& localName,
const XalanDOMChar* attrValue)
{
if(equals(localName, Constants::ATTRNAME_EXTENSIONELEMENTPREFIXES))
{
m_namespacesHandler.processExtensionElementPrefixes(attrValue, stylesheetTree.getNamespaces(), constructionContext);
return true;
}
else if (equals(localName, Constants::ATTRNAME_EXCLUDE_RESULT_PREFIXES))
{
m_namespacesHandler.processExcludeResultPrefixes(attrValue, stylesheetTree.getNamespaces(), constructionContext);
return true;
}
else
{
return false;
}
}
bool
ElemLiteralResult::shouldExcludeResultNamespaceNode(const XalanDOMString& theURI) const
{
return m_namespacesHandler.shouldExcludeResultNamespaceNode(
getStylesheet().getXSLTNamespaceURI(),
theURI);
}