blob: b9cc2fddcda05e104e5bd5e6f2263b0a8cec8073 [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 "AVT.hpp"
#include <xalanc/PlatformSupport/DOMStringHelper.hpp>
#include <xalanc/PlatformSupport/XalanMessageLoader.hpp>
#include <xalanc/PlatformSupport/StringTokenizer.hpp>
#include <xalanc/PlatformSupport/XalanUnicode.hpp>
#include <xalanc/DOMSupport/DOMServices.hpp>
#include "AVTPartSimple.hpp"
#include "AVTPartXPath.hpp"
#include "StylesheetConstructionContext.hpp"
namespace XALAN_CPP_NAMESPACE {
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
};
const XalanDOMString AVT::s_emptyString(XalanMemMgrs::getDummyMemMgr());
typedef XPathConstructionContext::GetCachedString GetCachedString;
/**
* 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(
StylesheetConstructionContext& constructionContext,
const Locator* locator,
const XalanDOMChar* name,
const XalanDOMChar* stringedValue,
const PrefixResolver& resolver) :
m_parts(0),
m_partsSize(0),
m_simpleString(0),
m_simpleStringLength(0),
m_name(constructionContext.getPooledString(name))
{
StringTokenizer tokenizer(stringedValue, theTokenDelimiterCharacters, true);
const StringTokenizer::size_type nTokens = tokenizer.countTokens();
if(nTokens < 2)
{
// Do the simple thing
m_simpleStringLength = length(stringedValue);
m_simpleString = constructionContext.allocateXalanDOMCharVector(stringedValue, m_simpleStringLength, false);
}
else
{
// This over-allocates, but we probably won't waste that much space. If necessary,
// we could tokenize twice, just counting the numbers of AVTPart instances we
// will need the first time.
m_parts = constructionContext.allocateAVTPartPointerVector(nTokens + 1);
XalanDOMString buffer(constructionContext.getMemoryManager());
XalanDOMString exprBuffer(constructionContext.getMemoryManager());
XalanDOMString t(constructionContext.getMemoryManager()); // base token
XalanDOMString lookahead(constructionContext.getMemoryManager()); // next token
while (tokenizer.hasMoreTokens())
{
if (lookahead.empty() == false)
{
t = lookahead;
lookahead.clear();
}
else
{
nextToken(constructionContext, locator, tokenizer, t);
}
if (t.length() == 1)
{
const XalanDOMChar theChar = t[0];
switch(theChar)
{
case(XalanUnicode::charLeftCurlyBracket):
{
// Attribute Value Template start
nextToken(constructionContext, locator, tokenizer, lookahead);
if(equals(lookahead, theLeftCurlyBracketString))
{
// Double braces mean escape to show brace
buffer.append(lookahead);
lookahead.clear();
break; // from switch
}
else
{
if(buffer.empty() == false)
{
assert(m_partsSize + 1 < nTokens);
m_parts[m_partsSize++] =
constructionContext.createAVTPart(
buffer.c_str(),
buffer.length());
buffer.clear();
}
exprBuffer.clear();
while (lookahead.empty() == false && !equals(lookahead, theRightCurlyBracketString))
{
if (lookahead.length() == 1)
{
switch(lookahead[0])
{
case XalanUnicode::charApostrophe:
case XalanUnicode::charQuoteMark:
{
// String start
exprBuffer.append(lookahead);
const XalanDOMChar quote[2] =
{
lookahead[0],
0
};
// Consume stuff 'till next quote
nextToken(constructionContext, locator, tokenizer, lookahead);
while(!equals(lookahead, quote))
{
exprBuffer.append(lookahead);
nextToken(constructionContext, locator, tokenizer, lookahead);
}
exprBuffer.append(lookahead);
break;
}
case XalanUnicode::charLeftCurlyBracket:
{
GetCachedString theGuard(constructionContext);
// What's another brace doing here?
constructionContext.problem(
StylesheetConstructionContext::eXSLTProcessor,
StylesheetConstructionContext::eError,
XalanMessageLoader::getMessage(
theGuard.get(),
XalanMessages::LeftBraceCannotAppearWithinExpression),
locator,
0);
break;
}
default:
// part of the template stuff, just add it.
exprBuffer.append(lookahead);
break;
} // end inner switch
} // end if lookahead length == 1
else
{
// part of the template stuff, just add it.
exprBuffer.append(lookahead);
}
nextToken(constructionContext, locator, tokenizer, lookahead);
} // end while(!equals(lookahead, "}"))
assert(equals(lookahead, theRightCurlyBracketString));
// Proper close of attribute template. Evaluate the
// expression.
buffer.clear();
assert(m_partsSize + 1 < nTokens);
m_parts[m_partsSize++] =
constructionContext.createAVTPart(
locator,
exprBuffer.c_str(),
exprBuffer.length(),
resolver);
lookahead.clear(); // breaks out of inner while loop
}
break;
}
case(XalanUnicode::charRightCurlyBracket):
{
nextToken(constructionContext, locator, tokenizer, lookahead);
if (equals(lookahead, theRightCurlyBracketString))
{
// Double brace mean escape to show brace
buffer.append(lookahead);
lookahead.clear(); // swallow
}
else
{
GetCachedString theGuard(constructionContext);
constructionContext.problem(
StylesheetConstructionContext::eXSLTProcessor,
StylesheetConstructionContext::eError,
XalanMessageLoader::getMessage(
theGuard.get(),
XalanMessages::UnmatchedWasFound),
locator,
0);
}
break;
}
default:
{
// Anything else just add to string.
buffer.append(1, theChar);
}
} // end switch t
} // end if length == 1
else
{
// Anything else just add to string.
buffer.append(t);
}
} // end while(tokenizer.hasMoreTokens())
if (buffer.empty() == false)
{
assert(m_partsSize + 1 < nTokens);
m_parts[m_partsSize++] =
constructionContext.createAVTPart(
buffer.c_str(),
buffer.length());
buffer.clear();
}
} // end else nTokens > 1
}
AVT::~AVT()
{
}
void
AVT::doEvaluate(
XalanDOMString& buf,
XalanNode* contextNode,
const PrefixResolver& prefixResolver,
XPathExecutionContext& executionContext) const
{
if(m_partsSize != 0)
{
for(size_type i = 0; i < m_partsSize; i++)
{
assert(m_parts[i] != 0);
m_parts[i]->evaluate(buf, contextNode, prefixResolver, executionContext);
}
}
}
void
AVT::doEvaluate(
XalanDOMString& buf,
const PrefixResolver& prefixResolver,
XPathExecutionContext& executionContext) const
{
if(m_partsSize != 0)
{
for(size_type i = 0; i < m_partsSize; i++)
{
assert(m_parts[i] != 0);
m_parts[i]->evaluate(buf, prefixResolver, executionContext);
}
}
}
void
AVT::nextToken(
StylesheetConstructionContext& constructionContext,
const Locator* locator,
StringTokenizer& tokenizer,
XalanDOMString& token)
{
if (tokenizer.hasMoreTokens() == false)
{
GetCachedString theGuard(constructionContext);
constructionContext.problem(
StylesheetConstructionContext::eXSLTProcessor,
StylesheetConstructionContext::eError,
XalanMessageLoader::getMessage(
theGuard.get(),
XalanMessages::AttributeValueTemplateHasMissing),
locator,
0);
}
else
{
tokenizer.nextToken(token);
}
}
}