blob: 917535d611756a851220c00d9cf9f8efd4febdd7 [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed 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 "FormatterToSourceTree.hpp"
#include <cassert>
#include <xercesc/sax/AttributeList.hpp>
#include <xalanc/XalanDOM/XalanDOMException.hpp>
#include <xalanc/XalanDOM/XalanDocumentFragment.hpp>
#include <xalanc/PlatformSupport/DOMStringHelper.hpp>
#include <xalanc/PlatformSupport/PrefixResolver.hpp>
#include "XalanSourceTreeComment.hpp"
#include "XalanSourceTreeDocument.hpp"
#include "XalanSourceTreeDocumentFragment.hpp"
#include "XalanSourceTreeElement.hpp"
#include "XalanSourceTreeHelper.hpp"
#include "XalanSourceTreeProcessingInstruction.hpp"
#include "XalanSourceTreeText.hpp"
XALAN_CPP_NAMESPACE_BEGIN
FormatterToSourceTree::FormatterToSourceTree(XalanSourceTreeDocument* theDocument) :
FormatterListener(OUTPUT_METHOD_DOM),
m_document(theDocument),
m_documentFragment(0),
m_currentElement(0),
m_elementStack(),
m_lastChild(0),
m_lastChildStack(),
m_textBuffer()
{
}
FormatterToSourceTree::FormatterToSourceTree(
XalanSourceTreeDocument* theDocument,
XalanSourceTreeDocumentFragment* theDocumentFragment) :
FormatterListener(OUTPUT_METHOD_DOM),
m_document(theDocument),
m_documentFragment(theDocumentFragment),
m_currentElement(0),
m_elementStack(),
m_lastChild(0),
m_lastChildStack(),
m_textBuffer()
{
assert(m_document != 0);
assert(m_documentFragment != 0);
}
FormatterToSourceTree::~FormatterToSourceTree()
{
}
void
FormatterToSourceTree::setDocumentLocator(const LocatorType* const /* locator */)
{
}
void
FormatterToSourceTree::startDocument()
{
m_currentElement = 0;
m_elementStack.clear();
m_lastChild = 0;
m_lastChildStack.clear();
m_lastChildStack.reserve(eDefaultStackSize);
clear(m_textBuffer);
reserve(m_textBuffer, eDefaultTextBufferSize);
// Push a dummy value for the current element, so we
// don't have to check for an empty stack in endElement().
m_elementStack.push_back(ElementStackType::value_type(0));
}
void
FormatterToSourceTree::endDocument()
{
// Pop off the dummy value that we pushed in
// startDocument()...
m_elementStack.pop_back();
assert(m_elementStack.empty() == true);
assert(m_lastChildStack.empty() == true);
assert(isEmpty(m_textBuffer) == true);
}
// A helper function to manage appending the new child.
template <class ParentNodeType, class ChildNodeType>
inline void
doAppendChildNode(
ParentNodeType* theParent,
XalanNode*& theLastChild,
ChildNodeType theNewChild)
{
assert(theParent != 0);
assert(theNewChild != 0);
if (theLastChild == 0)
{
theParent->appendChildNode(theNewChild);
}
else
{
XalanSourceTreeHelper::appendSibling(theLastChild, theNewChild);
theNewChild->setParent(theParent);
}
theLastChild = theNewChild;
}
// A helper function to manage appending the new child.
template <class ChildNodeType>
inline void
doAppendChildNode(
XalanSourceTreeDocument* theDocument,
XalanSourceTreeDocumentFragment* theDocumentFragment,
XalanSourceTreeElement* theCurrentElement,
XalanNode*& theLastChild,
ChildNodeType theNewChild)
{
assert(theDocument != 0);
assert(theNewChild != 0);
if (theCurrentElement == 0)
{
if (theDocumentFragment != 0)
{
doAppendChildNode(theDocumentFragment, theLastChild, theNewChild);
}
else
{
// If there is no current element. it means we haven't
// created the document element yet, so always append
// to the document, rather than the last child.
theDocument->appendChildNode(theNewChild);
}
}
else
{
doAppendChildNode(theCurrentElement, theLastChild, theNewChild);
}
}
void
FormatterToSourceTree::startElement(
const XMLCh* const name,
AttributeListType& attrs)
{
processAccumulatedText();
XalanSourceTreeElement* const theNewElement =
createElementNode(name, attrs, m_currentElement);
doAppendChildNode(
m_document,
m_documentFragment,
m_currentElement,
m_lastChild,
theNewElement);
m_elementStack.push_back(theNewElement);
m_lastChildStack.push_back(m_lastChild);
m_currentElement = theNewElement;
m_lastChild = 0;
}
void
FormatterToSourceTree::endElement(const XMLCh* const /* name */)
{
processAccumulatedText();
assert(m_elementStack.empty() == false);
// Pop the element of the stack...
m_elementStack.pop_back();
assert(m_elementStack.empty() == false);
// Get the element from the back of the
// stack.
m_currentElement = m_elementStack.back();
assert(m_lastChildStack.empty() == false);
m_lastChild = m_lastChildStack.back();
// Pop the last child stack
m_lastChildStack.pop_back();
}
void
FormatterToSourceTree::characters(
const XMLCh* const chars,
const unsigned int length)
{
if (m_documentFragment != 0)
{
doCharacters(chars, length);
}
else if (m_currentElement == 0)
{
if (isXMLWhitespace(chars) == false)
{
throw XalanDOMException(XalanDOMException::HIERARCHY_REQUEST_ERR);
}
}
else
{
append(m_textBuffer, chars, length);
}
}
void
FormatterToSourceTree::charactersRaw(
const XMLCh* const chars,
const unsigned int length)
{
assert(m_document != 0);
processAccumulatedText();
doProcessingInstruction(s_piTarget, s_piData);
characters(chars, length);
}
void
FormatterToSourceTree::entityReference(const XMLCh* const /* name */)
{
}
void
FormatterToSourceTree::ignorableWhitespace(
const XMLCh* const chars,
const unsigned int length)
{
assert(m_document != 0);
// Ignore any whitespace reported before the document element has been parsed.
if (m_elementStack.size() > 1)
{
assert(m_documentFragment != 0 || m_document->getDocumentElement() != 0);
processAccumulatedText();
assert(m_currentElement != 0);
doAppendChildNode(
m_currentElement,
m_lastChild,
m_document->createTextIWSNode(chars, length, m_currentElement));
}
else if(m_documentFragment != 0)
{
processAccumulatedText();
doAppendChildNode(
m_documentFragment,
m_lastChild,
m_document->createTextIWSNode(chars, length, m_currentElement));
}
}
void
FormatterToSourceTree::processingInstruction(
const XMLCh* const target,
const XMLCh* const data)
{
assert(m_document != 0);
processAccumulatedText();
doProcessingInstruction(target, data);
}
void
FormatterToSourceTree::resetDocument()
{
}
void
FormatterToSourceTree::comment(const XMLCh* const data)
{
assert(m_document != 0);
processAccumulatedText();
XalanSourceTreeComment* const theNewComment =
m_document->createCommentNode(data, length(data), m_currentElement);
doAppendChildNode(
m_document,
m_documentFragment,
m_currentElement,
m_lastChild,
theNewComment);
}
void
FormatterToSourceTree::cdata(
const XMLCh* const /* ch */,
const unsigned int /* length */)
{
}
void
FormatterToSourceTree::processAccumulatedText()
{
if (isEmpty(m_textBuffer) == false)
{
doCharacters(c_wstr(m_textBuffer), length(m_textBuffer));
clear(m_textBuffer);
}
}
void
FormatterToSourceTree::doCharacters(
const XMLCh* chars,
XalanDOMString::size_type length)
{
if (m_currentElement != 0)
{
doAppendChildNode(
m_currentElement,
m_lastChild,
m_document->createTextNode(chars, length, m_currentElement));
}
else if (m_documentFragment != 0)
{
doAppendChildNode(
m_documentFragment,
m_lastChild,
m_document->createTextNode(chars, length, m_currentElement));
}
else
{
throw XalanDOMException(XalanDOMException::HIERARCHY_REQUEST_ERR);
}
}
XalanSourceTreeElement*
FormatterToSourceTree::createElementNode(
const XalanDOMChar* name,
AttributeListType& attrs,
XalanSourceTreeElement* theParentElement)
{
if (m_prefixResolver != 0)
{
return m_document->createElementNode(name, attrs, *m_prefixResolver, theParentElement);
}
else
{
return m_document->createElementNode(name, attrs, theParentElement);
}
}
void
FormatterToSourceTree::doProcessingInstruction(
const XMLCh* target,
const XMLCh* data)
{
doAppendChildNode(
m_document,
m_documentFragment,
m_currentElement,
m_lastChild,
m_document->createProcessingInstructionNode(target, data));
}
XALAN_CPP_NAMESPACE_END