| /* |
| * 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 "ElemElement.hpp" |
| |
| |
| |
| #include <xercesc/sax/AttributeList.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 { |
| |
| |
| |
| ElemElement::ElemElement( |
| StylesheetConstructionContext& constructionContext, |
| Stylesheet& stylesheetTree, |
| const AttributeListType& atts, |
| XalanFileLoc lineNumber, |
| XalanFileLoc columnNumber) : |
| ElemUse(constructionContext, |
| stylesheetTree, |
| lineNumber, |
| columnNumber, |
| StylesheetConstructionContext::ELEMNAME_ELEMENT), |
| m_nameAVT(0), |
| m_namespaceAVT(0) |
| { |
| // Namespace aliases are not used for xsl:element, so |
| // turn them off... |
| // m_namespacesHandler.setProcessNamespaceAliaises(false); |
| |
| const XalanSize_t nAttrs = atts.getLength(); |
| |
| for (XalanSize_t i = 0; i < nAttrs; i++) |
| { |
| const XalanDOMChar* const aname = atts.getName(i); |
| |
| if(equals(aname, Constants::ATTRNAME_NAME)) |
| { |
| m_nameAVT = |
| constructionContext.createAVT(getLocator(), aname, atts.getValue(i), *this); |
| } |
| else if(equals(aname, Constants::ATTRNAME_NAMESPACE)) |
| { |
| m_namespaceAVT = |
| constructionContext.createAVT(getLocator(), aname, atts.getValue(i), *this); |
| } |
| else if(processUseAttributeSets( |
| constructionContext, |
| aname, |
| atts, |
| i) == false && |
| processSpaceAttr( |
| Constants::ELEMNAME_ELEMENT_WITH_PREFIX_STRING.c_str(), |
| aname, |
| atts, |
| i, |
| constructionContext) == false && |
| isAttrOK( |
| aname, |
| atts, |
| i, |
| constructionContext) == false) |
| { |
| error( |
| constructionContext, |
| XalanMessages::ElementHasIllegalAttribute_2Param, |
| Constants::ELEMNAME_ELEMENT_WITH_PREFIX_STRING.c_str(), |
| aname); |
| } |
| } |
| |
| if(0 == m_nameAVT) |
| { |
| error( |
| constructionContext, |
| XalanMessages::ElementMustHaveAttribute_2Param, |
| Constants::ELEMNAME_ELEMENT_WITH_PREFIX_STRING, |
| Constants::ATTRNAME_NAME); |
| } |
| } |
| |
| |
| |
| ElemElement::~ElemElement() |
| { |
| } |
| |
| |
| |
| const XalanDOMString& |
| ElemElement::getElementName() const |
| { |
| return Constants::ELEMNAME_ELEMENT_WITH_PREFIX_STRING; |
| } |
| |
| |
| |
| typedef const StylesheetExecutionContext::GetCachedString GetCachedString; |
| |
| #if !defined(XALAN_RECURSIVE_STYLESHEET_EXECUTION) |
| const ElemTemplateElement* |
| ElemElement::startElement(StylesheetExecutionContext& executionContext) const |
| { |
| XalanDOMString& elemName = executionContext.getAndPushCachedString(); |
| |
| m_nameAVT->evaluate(elemName, *this, executionContext); |
| |
| bool isIllegalElement = !XalanQName::isValidQName(elemName); |
| |
| if (isIllegalElement == true) |
| { |
| warn( |
| executionContext, |
| XalanMessages::IllegalElementName_1Param, |
| elemName); |
| |
| executionContext.pushSkipElementAttributes(true); |
| } |
| else |
| { |
| const GetCachedString elemNameSpaceGuard(executionContext); |
| |
| XalanDOMString& elemNameSpace = elemNameSpaceGuard.get(); |
| |
| if (m_namespaceAVT != 0) |
| { |
| m_namespaceAVT->evaluate(elemNameSpace, *this, executionContext); |
| } |
| |
| XalanDOMString::size_type namespaceLen = elemNameSpace.length(); |
| |
| XalanDOMString::size_type len = elemName.length(); |
| |
| const XalanDOMString::size_type indexOfNSSep = indexOf(elemName, XalanUnicode::charColon); |
| |
| const bool havePrefix = indexOfNSSep == len ? false : true; |
| |
| const GetCachedString prefixGuard(executionContext); |
| |
| XalanDOMString& prefix = prefixGuard.get(); |
| |
| if (havePrefix == true) |
| { |
| substring(elemName, prefix, 0, indexOfNSSep); |
| |
| const XalanDOMString* const theNamespace = |
| getNamespacesHandler().getNamespace(prefix); |
| |
| if(theNamespace == 0 && namespaceLen == 0) |
| { |
| warn( |
| executionContext, |
| XalanMessages::PrefixIsNotDeclared_1Param, |
| prefix); |
| |
| if (m_namespaceAVT != 0) |
| { |
| elemName.erase(0, indexOfNSSep + 1); |
| } |
| else |
| { |
| isIllegalElement = true; |
| |
| warn( |
| executionContext, |
| XalanMessages::IllegalElementName_1Param, |
| elemName); |
| } |
| } |
| else if (theNamespace != 0 && |
| namespaceLen == 0 && |
| equals(prefix, DOMServices::s_XMLNamespace) == false) |
| { |
| elemNameSpace = *theNamespace; |
| } |
| } |
| |
| if (isIllegalElement == false) |
| { |
| executionContext.startElement(elemName.c_str()); |
| |
| if(0 == m_namespaceAVT && |
| havePrefix == false ) |
| { |
| if (havePrefix == false) |
| { |
| fixupDefaultNamespace(executionContext); |
| } |
| } |
| else |
| { |
| if(havePrefix == false) |
| { |
| if (namespaceLen > 0) |
| { |
| const XalanDOMString* const theDefaultNamespace = |
| executionContext.getResultNamespaceForPrefix(s_emptyString); |
| |
| if (theDefaultNamespace == 0 || |
| equals(*theDefaultNamespace, elemNameSpace) == false) |
| { |
| executionContext.addResultAttribute( |
| DOMServices::s_XMLNamespace, |
| elemNameSpace); |
| } |
| } |
| else |
| { |
| // OK, the namespace we're generating is the default namespace, |
| // so let's make sure that we really need it. If we don't, |
| // we end up with another xmlns="" on the element we're |
| // generating. Although this isn't really an error, it's |
| // a bit unsightly, so let's suppress it... |
| const XalanDOMString& theParentDefaultNamespace = |
| getParentDefaultNamespace(); |
| |
| if (theParentDefaultNamespace.empty() == false || |
| executionContext.getResultNamespaceForPrefix(s_emptyString) != 0) |
| { |
| executionContext.addResultAttribute(DOMServices::s_XMLNamespace, elemNameSpace); |
| } |
| } |
| } |
| else |
| { |
| const XalanDOMString* const theNamespace = |
| executionContext.getResultNamespaceForPrefix(prefix); |
| |
| if (theNamespace == 0 || |
| equals(*theNamespace, elemNameSpace) == false) |
| { |
| prefix.insert(0, DOMServices::s_XMLNamespaceWithSeparator); |
| |
| executionContext.addResultAttribute(prefix, elemNameSpace); |
| } |
| } |
| } |
| } |
| |
| if (isIllegalElement == true) |
| { |
| executionContext.pushSkipElementAttributes(true); |
| } |
| else |
| { |
| ElemUse::startElement(executionContext); |
| |
| executionContext.pushSkipElementAttributes(false); |
| } |
| } |
| |
| return beginExecuteChildren(executionContext); |
| } |
| |
| |
| |
| void |
| ElemElement::endElement(StylesheetExecutionContext& executionContext) const |
| { |
| endExecuteChildren(executionContext); |
| |
| bool ignoreAttributeElements = executionContext.popSkipElementAttributes(); |
| |
| const XalanDOMString& elemName = executionContext.getAndPopCachedString(); |
| |
| if (!ignoreAttributeElements) |
| { |
| executionContext.endElement(elemName.c_str()); |
| ElemUse::endElement(executionContext); |
| } |
| } |
| |
| |
| |
| bool |
| ElemElement::executeChildElement( |
| StylesheetExecutionContext& executionContext, |
| const ElemTemplateElement* element) const |
| { |
| return !(element->getXSLToken() == StylesheetConstructionContext::ELEMNAME_ATTRIBUTE |
| && executionContext.getSkipElementAttributes() == true); |
| } |
| #endif |
| |
| |
| |
| #if defined(XALAN_RECURSIVE_STYLESHEET_EXECUTION) |
| void |
| ElemElement::execute(StylesheetExecutionContext& executionContext) const |
| { |
| const GetCachedString elemNameGuard(executionContext); |
| |
| XalanDOMString& elemName = elemNameGuard.get(); |
| |
| m_nameAVT->evaluate(elemName, *this, executionContext); |
| |
| bool isIllegalElement = !XalanQName::isValidQName(elemName); |
| |
| if (isIllegalElement == true) |
| { |
| warn( |
| executionContext, |
| XalanMessages::IllegalElementName_1Param, |
| elemName); |
| |
| ElemUse::doExecute(executionContext, false); |
| |
| doExecuteChildren(executionContext, true); |
| } |
| else |
| { |
| const GetCachedString elemNameSpaceGuard(executionContext); |
| |
| XalanDOMString& elemNameSpace = elemNameSpaceGuard.get(); |
| |
| if (m_namespaceAVT != 0) |
| { |
| m_namespaceAVT->evaluate(elemNameSpace, *this, executionContext); |
| } |
| |
| XalanDOMString::size_type namespaceLen = length(elemNameSpace); |
| |
| bool foundResultNamespaceForPrefix = false; |
| |
| XalanDOMString::size_type len = length(elemName); |
| |
| const XalanDOMString::size_type indexOfNSSep = indexOf(elemName, XalanUnicode::charColon); |
| |
| const bool havePrefix = indexOfNSSep == len ? false : true; |
| |
| const GetCachedString prefixGuard(executionContext); |
| |
| XalanDOMString& prefix = prefixGuard.get(); |
| |
| if (havePrefix == true) |
| { |
| substring(elemName, prefix, 0, indexOfNSSep); |
| |
| const XalanDOMString* const theNamespace = |
| executionContext.getResultNamespaceForPrefix(prefix); |
| |
| if (theNamespace != 0) |
| { |
| foundResultNamespaceForPrefix = true; |
| } |
| else |
| { |
| const XalanDOMString* const theNamespace = |
| getNamespacesHandler().getNamespace(prefix); |
| |
| if(theNamespace == 0 && namespaceLen == 0) |
| { |
| warn( |
| executionContext, |
| XalanMessages::PrefixIsNotDeclared_1Param, |
| prefix); |
| |
| if (m_namespaceAVT != 0) |
| { |
| elemName.erase(0, indexOfNSSep + 1); |
| } |
| else |
| { |
| isIllegalElement = true; |
| |
| warn( |
| executionContext, |
| XalanMessages::IllegalElementName_1Param, |
| elemName); |
| } |
| } |
| else if (theNamespace != 0 && |
| namespaceLen == 0 && |
| equals(prefix, DOMServices::s_XMLNamespace) == false) |
| { |
| elemNameSpace = *theNamespace; |
| } |
| } |
| } |
| |
| if (isIllegalElement == false) |
| { |
| executionContext.startElement(elemName.c_str()); |
| |
| if(0 == m_namespaceAVT && |
| (havePrefix == false || foundResultNamespaceForPrefix == true)) |
| { |
| if (havePrefix == false) |
| { |
| fixupDefaultNamespace(executionContext); |
| } |
| } |
| else |
| { |
| if(havePrefix == false) |
| { |
| if (namespaceLen > 0) |
| { |
| const XalanDOMString* const theDefaultNamespace = |
| executionContext.getResultNamespaceForPrefix(s_emptyString); |
| |
| if (theDefaultNamespace == 0 || |
| equals(*theDefaultNamespace, elemNameSpace) == false) |
| { |
| executionContext.addResultAttribute( |
| DOMServices::s_XMLNamespace, |
| elemNameSpace); |
| } |
| } |
| else |
| { |
| // OK, the namespace we're generating is the default namespace, |
| // so let's make sure that we really need it. If we don't, |
| // we end up with another xmlns="" on the element we're |
| // generating. Although this isn't really an error, it's |
| // a bit unsightly, so let's suppress it... |
| const XalanDOMString& theParentDefaultNamespace = |
| getParentDefaultNamespace(); |
| |
| if (length(theParentDefaultNamespace) == 0) |
| { |
| if (executionContext.getResultNamespaceForPrefix(s_emptyString) != 0) |
| { |
| executionContext.addResultAttribute(DOMServices::s_XMLNamespace, elemNameSpace); |
| } |
| } |
| else |
| { |
| executionContext.addResultAttribute(DOMServices::s_XMLNamespace, elemNameSpace); |
| } |
| } |
| } |
| else |
| { |
| const XalanDOMString* const theNamespace = |
| executionContext.getResultNamespaceForPrefix(prefix); |
| |
| if (theNamespace == 0 || |
| equals(*theNamespace, elemNameSpace) == false) |
| { |
| insert(prefix, 0, DOMServices::s_XMLNamespaceWithSeparator); |
| |
| executionContext.addResultAttribute(prefix, elemNameSpace); |
| } |
| } |
| } |
| } |
| |
| if (isIllegalElement == true) |
| { |
| ElemUse::doExecute(executionContext, false); |
| |
| doExecuteChildren(executionContext, true); |
| } |
| else |
| { |
| ElemUse::doExecute(executionContext, true); |
| |
| doExecuteChildren(executionContext, false); |
| |
| executionContext.endElement(elemName.c_str()); |
| } |
| } |
| } |
| |
| |
| |
| void |
| ElemElement::doExecuteChildren( |
| StylesheetExecutionContext& executionContext, |
| bool skipAttributeChildren) const |
| { |
| if (skipAttributeChildren == false) |
| { |
| // If we should execute all children, then just call |
| // executeChildren()... |
| executeChildren(executionContext); |
| } |
| else |
| { |
| StylesheetExecutionContext::PushAndPopElementFrame thePushAndPop(executionContext, this); |
| |
| for (ElemTemplateElement* node = getFirstChildElem(); node != 0; node = node->getNextSiblingElem()) |
| { |
| if (node->getXSLToken() != StylesheetConstructionContext::ELEMNAME_ATTRIBUTE) |
| { |
| node->execute(executionContext); |
| } |
| } |
| } |
| } |
| #endif |
| |
| |
| |
| void |
| ElemElement::namespacesPostConstruction( |
| StylesheetConstructionContext& constructionContext, |
| const NamespacesHandler& theParentHandler, |
| NamespacesHandler& theHandler) |
| { |
| theHandler.postConstruction( |
| constructionContext, |
| false, |
| getElementName(), |
| &theParentHandler); |
| } |
| |
| |
| |
| void |
| ElemElement::fixupDefaultNamespace(StylesheetExecutionContext& executionContext) const |
| { |
| // OK, now let's check to make sure we don't have to change the default namespace... |
| const XalanDOMString* const theCurrentDefaultNamespace = |
| executionContext.getResultNamespaceForPrefix(s_emptyString); |
| |
| const XalanDOMString* const theElementDefaultNamespace = |
| getNamespacesHandler().getNamespace(s_emptyString); |
| |
| if (theCurrentDefaultNamespace != 0) |
| { |
| 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) |
| { |
| // There is a default namespace, but it's different from the current one, |
| // so we have to change it. |
| executionContext.addResultAttribute(DOMServices::s_XMLNamespace, *theElementDefaultNamespace); |
| } |
| } |
| else if (theElementDefaultNamespace != 0) |
| { |
| executionContext.addResultAttribute(DOMServices::s_XMLNamespace, *theElementDefaultNamespace); |
| } |
| } |
| |
| |
| |
| const XalanDOMString& |
| ElemElement::getParentDefaultNamespace() const |
| { |
| const ElemTemplateElement* const theParent = |
| getParentNodeElem(); |
| |
| if (theParent == 0) |
| { |
| return s_emptyString; |
| } |
| else |
| { |
| const XalanDOMString* const theParentDefaultNamespace = |
| theParent->getNamespacesHandler().getNamespace(s_emptyString); |
| |
| if (theParentDefaultNamespace == 0) |
| { |
| return s_emptyString; |
| } |
| else |
| { |
| return *theParentDefaultNamespace; |
| } |
| } |
| } |
| |
| |
| |
| } |