blob: e1ef47a4bea682926837dcdc51d0cf80dc0c725e [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 "AVT.hpp"
#include <algorithm>
#include <Include/STLHelper.hpp>
#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/StringTokenizer.hpp>
#include <PlatformSupport/XalanUnicode.hpp>
#include <DOMSupport/DOMServices.hpp>
#include "AVTPartSimple.hpp"
#include "AVTPartXPath.hpp"
#include "StylesheetConstructionContext.hpp"
static const XalanDOMChar theTokenDelimiterCharacters[] =
{
XalanUnicode::charLeftCurlyBracket,
XalanUnicode::charRightCurlyBracket,
XalanUnicode::charApostrophe,
XalanUnicode::charQuoteMark,
0
};
static const XalanDOMChar theLeftCurlyBracketString[] =
{
XalanUnicode::charLeftCurlyBracket,
0
};
static const XalanDOMChar theRightCurlyBracketString[] =
{
XalanUnicode::charRightCurlyBracket,
0
};
/**
* Construct an AVT by parsing the string, and either
* constructing a vector of AVTParts, or simply hold
* on to the string if the AVT is simple.
*/
AVT::AVT(
const Locator* locator,
const XalanDOMChar* name,
const XalanDOMChar* type,
const XalanDOMChar* stringedValue,
const PrefixResolver& resolver,
StylesheetConstructionContext& constructionContext) :
m_parts(),
m_simpleString(),
// $$$ ToDo: Explicit XalanDOMString constructor
m_name(XalanDOMString(name)),
m_prefix(getPrefix(name)),
m_pcType(type)
{
StringTokenizer tokenizer(stringedValue, theTokenDelimiterCharacters, true);
const StringTokenizer::size_type nTokens = tokenizer.countTokens();
if(nTokens < 2)
{
m_simpleString = stringedValue; // then do the simple thing
}
else
{
m_parts.reserve(nTokens + 1);
XalanDOMString buffer;
XalanDOMString exprBuffer;
XalanDOMString t; // base token
XalanDOMString lookahead; // next token
XalanDOMString error; // if non-null, break from loop
while(tokenizer.hasMoreTokens())
{
if(length(lookahead))
{
t = lookahead;
clear(lookahead);
}
else
{
nextToken(constructionContext, locator, tokenizer, t);
}
if(length(t) == 1)
{
const XalanDOMChar theChar = charAt(t, 0);
switch(theChar)
{
case(XalanUnicode::charLeftCurlyBracket):
{
// Attribute Value Template start
nextToken(constructionContext, locator, tokenizer, lookahead);
if(equals(lookahead, theLeftCurlyBracketString))
{
// Double curlys mean escape to show curly
append(buffer, lookahead);
clear(lookahead);
break; // from switch
}
else
{
if(length(buffer) > 0)
{
m_parts.push_back(new AVTPartSimple(buffer));
clear(buffer);
}
clear(exprBuffer);
while(length(lookahead) > 0 && !equals(lookahead, theRightCurlyBracketString))
{
if(length(lookahead) == 1)
{
switch(charAt(lookahead, 0))
{
case XalanUnicode::charApostrophe:
case XalanUnicode::charQuoteMark:
{
// String start
append(exprBuffer, lookahead);
const XalanDOMString quote = lookahead;
// Consume stuff 'till next quote
nextToken(constructionContext, locator, tokenizer, lookahead);
while(!equals(lookahead, quote))
{
append(exprBuffer, lookahead);
nextToken(constructionContext, locator, tokenizer, lookahead);
}
append(exprBuffer,lookahead);
break;
}
case XalanUnicode::charLeftCurlyBracket:
{
// What's another curly doing here?
error = TranscodeFromLocalCodePage("Error: Can not have \"{\" within expression.");
break;
}
default:
{
// part of the template stuff, just add it.
append(exprBuffer, lookahead);
}
} // end inner switch
} // end if lookahead length == 1
else
{
// part of the template stuff, just add it.
append(exprBuffer,lookahead);
}
nextToken(constructionContext, locator, tokenizer, lookahead);
} // end while(!equals(lookahead, "}"))
assert(equals(lookahead, theRightCurlyBracketString));
// Proper close of attribute template. Evaluate the
// expression.
clear(buffer);
const XPath* const xpath =
constructionContext.createXPath(
locator,
exprBuffer,
resolver);
assert(xpath != 0);
m_parts.push_back(new AVTPartXPath(xpath));
clear(lookahead); // breaks out of inner while loop
if(length(error) > 0)
{
break; // from inner while loop
}
}
break;
}
case(XalanUnicode::charRightCurlyBracket):
{
nextToken(constructionContext, locator, tokenizer, lookahead);
if(equals(lookahead, theRightCurlyBracketString))
{
// Double curlys mean escape to show curly
append(buffer, lookahead);
clear(lookahead); // swallow
}
else
{
// Illegal, I think...
constructionContext.warn("Found \"}\" but no attribute template open!");
append(buffer, theRightCurlyBracketString);
// leave the lookahead to be processed by the next round.
}
break;
}
default:
{
const XalanDOMString s(&theChar, 1);
// Anything else just add to string.
append(buffer, s);
}
} // end switch t
} // end if length == 1
else
{
// Anything else just add to string.
append(buffer,t);
}
if(length(error) > 0)
{
constructionContext.warn("Attr Template, " + error);
break;
}
} // end while(tokenizer.hasMoreTokens())
if(length(buffer) > 0)
{
m_parts.push_back(new AVTPartSimple(buffer));
clear(buffer);
}
} // end else nTokens > 1
if(m_parts.empty() && length(m_simpleString) == 0)
{
// Error?
clear(m_simpleString);
}
else if (m_parts.size() < m_parts.capacity())
{
AVTPartPtrVectorType(m_parts).swap(m_parts);
}
}
AVT::~AVT()
{
#if !defined(XALAN_NO_NAMESPACES)
using std::for_each;
#endif
// Clean up all entries in the vector.
for_each(m_parts.begin(),
m_parts.end(),
DeleteFunctor<AVTPart>());
}
void
AVT::evaluate(
XalanDOMString& buf,
XalanNode* contextNode,
const PrefixResolver& prefixResolver,
XPathExecutionContext& executionContext) const
{
if(length(m_simpleString) > 0)
{
buf = m_simpleString;
}
else
{
clear(buf);
if(m_parts.empty() == false)
{
const AVTPartPtrVectorType::size_type n = m_parts.size();
for(AVTPartPtrVectorType::size_type i = 0; i < n; i++)
{
assert(m_parts[i] != 0);
m_parts[i]->evaluate(buf, contextNode, prefixResolver, executionContext);
}
}
}
}
void
AVT::nextToken(
StylesheetConstructionContext& constructionContext,
const Locator* locator,
StringTokenizer& tokenizer,
XalanDOMString& token)
{
if (tokenizer.hasMoreTokens() == false)
{
constructionContext.error(
"The attribute value template has a missing a '}'",
0,
locator);
}
else
{
tokenizer.nextToken(token);
}
}
XalanDOMString
AVT::getPrefix(const XalanDOMChar* theName)
{
if (startsWith(theName, DOMServices::s_XMLNamespaceWithSeparator) == true)
{
return substring(theName, DOMServices::s_XMLNamespaceWithSeparatorLength);
}
else
{
return XalanDOMString();
}
}