void DOMLSSerializerImpl::processNode()

in src/xercesc/dom/impl/DOMLSSerializerImpl.cpp [631:1315]


void DOMLSSerializerImpl::processNode(const DOMNode* const nodeToWrite, int level)
{

    // Get the name and value out for convenience
    const XMLCh*    nodeName = nodeToWrite->getNodeName();
    const XMLCh*    nodeValue = nodeToWrite->getNodeValue();
    XMLSize_t       lent = XMLString::stringLen(nodeValue);

    switch (nodeToWrite->getNodeType())
    {
    case DOMNode::TEXT_NODE:
        {
            if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
                break;

            ensureValidString(nodeToWrite, nodeValue);
            if (getFeature(FORMAT_PRETTY_PRINT_ID))
            {
                fLineFeedInTextNodePrinted = false;
                fLastWhiteSpaceInTextNode = 0;

                if(XMLChar1_0::isAllSpaces(nodeValue, XMLString::stringLen(nodeValue)))
                {
                    // skips whitespace-only text nodes unless whitespace-in-element is set.
                    if (!getFeature(WHITESPACE_IN_ELEMENT_CONTENT_ID))
                    {
                        break;
                    }
                    else
                    {
                        //
                        // we need to trace if newline(s) have been printed out
                        // to avoid generate extra newline for pretty printing,
                        // as well as the number of whitespaces after the last
                        // newline character to do indentation properly.
                        //
                        int pos = XMLString::lastIndexOf(nodeValue, chLF);
                        if (-1 != pos)
                        {
                            fLineFeedInTextNodePrinted = true;
                            fLastWhiteSpaceInTextNode = (unsigned int)(lent - pos);
                        }
                        else
                        {
                            // for those platforms using chCR alone as
                            // a newline character
                            pos = XMLString::lastIndexOf(nodeValue, chCR);
                            if (-1 != pos)
                            {
                                fLineFeedInTextNodePrinted = true;
                                fLastWhiteSpaceInTextNode = (unsigned int)(lent - pos);
                            }
                        }
                    }
                }
            }

            setURCharRef();      // character data
            fFormatter->formatBuf(nodeValue, lent, XMLFormatter::CharEscapes);
            break;
        }

    case DOMNode::PROCESSING_INSTRUCTION_NODE:
        {
            if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
                break;

            ensureValidString(nodeToWrite, nodeName);
            ensureValidString(nodeToWrite, nodeValue);

            if(level == 1 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID))
                printNewLine();

            printNewLine();
            printIndent(level);

            TRY_CATCH_THROW
            (
                *fFormatter << XMLFormatter::NoEscapes << gStartPI << nodeName;
                if (lent > 0)
                {
                    *fFormatter << chSpace << nodeValue;
                }
                *fFormatter << gEndPI;
            )
            break;
        }

    case DOMNode::DOCUMENT_NODE: // Not to be shown to Filter
        {

            // output BOM if needed
            processBOM();

            setURCharRef();
            const DOMDocument *docu = (const DOMDocument*)nodeToWrite;

            //[23] XMLDecl      ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
            //[24] VersionInfo  ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
            //[80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName
            //[32] SDDecl       ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'))
            //

            if (getFeature(XML_DECLARATION)) {
                // use the version and encoding resolved
                *fFormatter << gXMLDecl_VersionInfo << fDocumentVersion << gXMLDecl_separator;
                *fFormatter << gXMLDecl_EncodingDecl << fEncodingUsed << gXMLDecl_separator;

                const XMLCh* st = (docu->getXmlStandalone())? XMLUni::fgYesString : XMLUni::fgNoString;
                *fFormatter << gXMLDecl_SDDecl << st << gXMLDecl_separator;

                *fFormatter << gXMLDecl_endtag;
            }

            DOMNodeSPtr child = nodeToWrite->getFirstChild();
            while( child != 0)
            {
                processNode(child, level);
                child = child->getNextSibling();
            }
            printNewLine();
            break;
        }

    case DOMNode::DOCUMENT_FRAGMENT_NODE:
        {

            setURCharRef();

            DOMNode *child = nodeToWrite->getFirstChild();
            while( child != 0)
            {
                processNode(child, level);
                child = child->getNextSibling();
            }
            printNewLine();
            break;
        }

    case DOMNode::ELEMENT_NODE:
        {
            DOMNodeFilter::FilterAction filterAction = checkFilter(nodeToWrite);

            if ( filterAction == DOMNodeFilter::FILTER_REJECT)
                break;

            if (!fLineFeedInTextNodePrinted)
            {
                if(level == 1 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID))
                    printNewLine();

                printNewLine();
            }
            else
            {
                fLineFeedInTextNodePrinted = false;
            }

            printIndent(level);

            //track the line number the current node begins on
            int nodeLine = fCurrentLine;

            // add an entry in the namespace stack
            RefHashTableOf<XMLCh>* namespaceMap=NULL;

            if ( filterAction == DOMNodeFilter::FILTER_ACCEPT)
            {
                //           this element    attributes   child elements
                // accept        yes             yes           yes
                // skip          no              no            yes
                //
                TRY_CATCH_THROW
                (
                // The name has to be representable without any escapes
                    *fFormatter  << XMLFormatter::NoEscapes
                                 << chOpenAngle << nodeName;
                )

                // Output any attributes on this element
                setURCharRef();
                DOMNamedNodeMap *attributes = nodeToWrite->getAttributes();
                XMLSize_t attrCount = attributes->getLength();

                // check if the namespace for the current node is already defined
                const XMLCh* prefix = nodeToWrite->getPrefix();
                const XMLCh* uri = nodeToWrite->getNamespaceURI();
                if((uri && uri[0]) || ((prefix==0 || prefix[0]==0) && isDefaultNamespacePrefixDeclared()))
                {
                    if(prefix==0 || prefix[0]==0)
                        prefix=XMLUni::fgZeroLenString;
                    if(!isNamespaceBindingActive(prefix, uri))
                    {
                        if(namespaceMap==NULL)
                        {
                            namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager);
                            fNamespaceStack->addElement(namespaceMap);
                        }
                        namespaceMap->put((void*)prefix,(XMLCh*)uri);
                        *fFormatter  << XMLFormatter::NoEscapes
                                     << chSpace << XMLUni::fgXMLNSString;
                        if(!XMLString::equals(prefix,XMLUni::fgZeroLenString))
                            *fFormatter  << chColon << prefix;
                        *fFormatter  << chEqual << chDoubleQuote
                                     << XMLFormatter::AttrEscapes
                                     << uri
                                     << XMLFormatter::NoEscapes
                                     << chDoubleQuote;
                    }
                }

                bool discard = getFeature(DISCARD_DEFAULT_CONTENT_ID);
                for (XMLSize_t i = 0; i < attrCount; i++)
                {
                    DOMAttrSPtr  attribute = (DOMAttr*)attributes->item(i);

                    // Not to be shown to Filter

                    //
                    //"discard-default-content"
                    //    true
                    //    [required] (default)
                    //    Use whatever information available to the implementation
                    //  (i.e. XML schema, DTD, the specified flag on Attr nodes,
                    //  and so on) to decide what attributes and content should be
                    //  discarded or not.
                    //  Note that the specified flag on Attr nodes in itself is
                    //  not always reliable, it is only reliable when it is set
                    //  to false since the only case where it can be set to false
                    //  is if the attribute was created by the implementation.
                    //  The default content won't be removed if an implementation
                    //  does not have any information available.
                    //    false
                    //    [required]
                    //    Keep all attributes and all content.
                    //
                    if (discard && !((DOMAttr*)attribute )->getSpecified())
                        continue;
                    //
                    //  Again the name has to be completely representable. But the
                    //  attribute can have refs and requires the attribute style
                    //  escaping.
                    //

                    // if this attribute is a namespace declaration, add it to the namespace map for the current level
                    const XMLCh* ns = attribute->getNamespaceURI();
                    if (ns != 0 )
                    {
                        if(XMLString::equals(ns, XMLUni::fgXMLNSURIName))
                        {
                            if(namespaceMap==NULL)
                            {
                                namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager);
                                fNamespaceStack->addElement(namespaceMap);
                            }
                            const XMLCh* nsPrefix = attribute->getLocalName();
                            if(XMLString::equals(attribute->getNodeName(),XMLUni::fgXMLNSString))
                                nsPrefix = XMLUni::fgZeroLenString;
                            if(namespaceMap->containsKey((void*)nsPrefix))
                                continue;
                            namespaceMap->put((void*)attribute->getLocalName(),(XMLCh*)attribute->getNodeValue());
                        }
                        else if(!XMLString::equals(ns, XMLUni::fgXMLURIName))
                        {
                            // check if the namespace for the current node is already defined
                            const XMLCh* prefix = attribute->getPrefix();
                            if(prefix && prefix[0])
                            {
                                const XMLCh* uri = attribute->getNamespaceURI();
                                if(!isNamespaceBindingActive(prefix, uri))
                                {
                                    if(namespaceMap==NULL)
                                    {
                                        namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager);
                                        fNamespaceStack->addElement(namespaceMap);
                                    }
                                    namespaceMap->put((void*)prefix,(XMLCh*)uri);
                                    *fFormatter  << XMLFormatter::NoEscapes
                                                 << chSpace << XMLUni::fgXMLNSString << chColon << prefix
                                                 << chEqual << chDoubleQuote
                                                 << XMLFormatter::AttrEscapes
                                                 << uri
                                                 << XMLFormatter::NoEscapes
                                                 << chDoubleQuote;
                                }
                            }
                        }
                    }
                    if (XMLString::equals(ns, XMLUni::fgXMLNSURIName) || checkFilter(attribute) == DOMNodeFilter::FILTER_ACCEPT)
                    {
                        *fFormatter  << XMLFormatter::NoEscapes
                                     << chSpace << attribute->getNodeName()
                                     << chEqual << chDoubleQuote
                                     << XMLFormatter::AttrEscapes;
                        if (getFeature(ENTITIES_ID))
                        {
                            DOMNodeSPtr child = attribute->getFirstChild();
                            while( child != 0)
                            {
                                if(child->getNodeType()==DOMNode::TEXT_NODE)
                                {
                                    ensureValidString(attribute, child->getNodeValue());
                                    *fFormatter  << child->getNodeValue();
                                }
                                else if(child->getNodeType()==DOMNode::ENTITY_REFERENCE_NODE)
                                    *fFormatter << XMLFormatter::NoEscapes
                                                << chAmpersand << child->getNodeName() << chSemiColon
                                                << XMLFormatter::AttrEscapes;
                                child = child->getNextSibling();
                            }
                        }
                        else
                        {
                            ensureValidString(attribute, attribute->getNodeValue());
                            *fFormatter  << attribute->getNodeValue();
                        }
                        *fFormatter  << XMLFormatter::NoEscapes
                                     << chDoubleQuote;
                    }
                } // end of for
            } // end of FILTER_ACCEPT

            level++;

            // FILTER_SKIP may start from here

            //
            //  Test for the presence of children, which includes both
            //  text content and nested elements.
            //
            DOMNodeSPtr child = nodeToWrite->getFirstChild();
            if (child != 0)
            {
                // There are children. Close start-tag, and output children.
                // No escapes are legal here
                if (filterAction == DOMNodeFilter::FILTER_ACCEPT)
                    *fFormatter << XMLFormatter::NoEscapes << chCloseAngle;

                while( child != 0)
                {
                    processNode(child, level);
                    child = child->getNextSibling();
                }

                level--;

                if (filterAction == DOMNodeFilter::FILTER_ACCEPT)
                {
                    //if we are not on the same line as when we started
                    //this node then print a new line and indent
                    if(nodeLine != fCurrentLine)
                    {
                        if (!fLineFeedInTextNodePrinted)
                        {
                            printNewLine();
                        }
                        else
                        {
                            fLineFeedInTextNodePrinted = false;
                        }

                        if(nodeLine != fCurrentLine && level == 0 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID))
                            printNewLine();

                        printIndent(level);
                    }
                    TRY_CATCH_THROW
                    (
                         *fFormatter << XMLFormatter::NoEscapes << gEndElement
                                     << nodeName << chCloseAngle;
                    )

                }
            }
            else
            {
                level--;

                //
                //  There were no children. Output the short form close of
                //  the element start tag, making it an empty-element tag.
                //
                if (filterAction == DOMNodeFilter::FILTER_ACCEPT)
                {
                    TRY_CATCH_THROW
                    (
                        *fFormatter << XMLFormatter::NoEscapes << chForwardSlash << chCloseAngle;
                    )
                }
            }

            // remove the namespace map at this level
            if(namespaceMap!=NULL)
                fNamespaceStack->removeLastElement();

            break;
        }
    case DOMNode::ATTRIBUTE_NODE:
        {
            if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
                break;

            const XMLCh* localName = nodeToWrite->getLocalName();

            // check if this is a DOM Level 1 Node
            if(localName == 0)
                *fFormatter  << XMLFormatter::NoEscapes
                             << nodeToWrite->getNodeName();
            else
                *fFormatter  << XMLFormatter::NoEscapes
                             << chOpenCurly << nodeToWrite->getNamespaceURI()
                             << chCloseCurly << localName;
            *fFormatter  << chEqual << chDoubleQuote
                         << XMLFormatter::AttrEscapes;
            if (getFeature(ENTITIES_ID))
            {
                DOMNodeSPtr child = nodeToWrite->getFirstChild();
                while( child != 0)
                {
                    if(child->getNodeType()==DOMNode::TEXT_NODE)
                    {
                        ensureValidString(nodeToWrite, child->getNodeValue());
                        *fFormatter  << child->getNodeValue();
                    }
                    else if(child->getNodeType()==DOMNode::ENTITY_REFERENCE_NODE)
                        *fFormatter << XMLFormatter::NoEscapes
                                    << chAmpersand << child->getNodeName() << chSemiColon
                                    << XMLFormatter::AttrEscapes;
                    child = child->getNextSibling();
                }
            }
            else
            {
                ensureValidString(nodeToWrite, nodeValue);
                *fFormatter  << nodeValue;
            }
            *fFormatter  << XMLFormatter::NoEscapes
                         << chDoubleQuote;

            break;
        }
    case DOMNode::ENTITY_REFERENCE_NODE:
        {
            //"entities"
            //true
            //[required] (default)
            //Keep EntityReference and Entity nodes in the document.

            //false
            //[optional]
            //Remove all EntityReference and Entity nodes from the document,
            //       putting the entity expansions directly in their place.
            //       Text nodes are into "normal" form.
            //Only EntityReference nodes to non-defined entities are kept in the document.

            if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
                break;

            if (getFeature(ENTITIES_ID))
            {
                TRY_CATCH_THROW
                (
                    *fFormatter << XMLFormatter::NoEscapes << chAmpersand
                                << nodeName << chSemiColon;
                )
            }
            else
            {
                // check if the referenced entity is defined or not
                if (nodeToWrite->getOwnerDocument()->getDoctype()->getEntities()->getNamedItem(nodeName))
                {
                    DOMNodeSPtr child;
                    for (child = nodeToWrite->getFirstChild();
                    child != 0;
                    child = child->getNextSibling())
                    {
                        processNode(child, level);
                    }
                }
                else
                {
                    TRY_CATCH_THROW
                   (
                        *fFormatter<<XMLFormatter::NoEscapes<<chAmpersand<<nodeName<<chSemiColon;
                    )
                }
            }
            break;
        }

        //
        //  feature:split_cdata_sections     occurence of ]]>   unrep-char
        //  ===============================================================
        //          true                        split            split
        //          false                       fails            fails
        //
    case DOMNode::CDATA_SECTION_NODE:
        {
            if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
                break;

            if (getFeature(SPLIT_CDATA_SECTIONS_ID))
            {
                // it is fairly complicated and we process this
                // in a separate function.
                procCdataSection(nodeValue, nodeToWrite);
            }
            else
            {
                ensureValidString(nodeToWrite, nodeValue);
                // search for "]]>", the node value is not supposed to have this
                if (XMLString::patternMatch(nodeValue, gEndCDATA) != -1)
                {
                    reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, XMLDOMMsg::Writer_NestedCDATA);
                }

                TRY_CATCH_THROW
                (
                    // transcoder throws exception for unrep chars
                    *fFormatter << XMLFormatter::NoEscapes << gStartCDATA << nodeValue << gEndCDATA;
                )
            }

            break;
        }

    case DOMNode::COMMENT_NODE:
        {
            if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
                break;

            ensureValidString(nodeToWrite, nodeValue);

            // Figure out if we want pretty-printing for this comment.
            // If this comment node does not have any element siblings
            // (i.e., it is a text node) then we don't want to add any
            // whitespaces since that might be significant to the
            // application. Otherwise we want pretty-printing.
            //

            bool pretty = (level == 0); // Document-level comments.

            if (!pretty)
            {
                // See if we have any element siblings.
                //
                const DOMNode* s = nodeToWrite->getNextSibling ();

                while (s != 0 && s->getNodeType () != DOMNode::ELEMENT_NODE)
                    s = s->getNextSibling ();

                if (s != 0)
                    pretty = true;
                else
                {
                    s = nodeToWrite->getPreviousSibling ();

                    while (s != 0 && s->getNodeType () != DOMNode::ELEMENT_NODE)
                        s = s->getPreviousSibling ();

                    if (s != 0)
                       pretty = true;
                }
            }

            if (pretty)
            {
                if(level == 1 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID))
                    printNewLine();

                printNewLine();
                printIndent(level);
            }

            TRY_CATCH_THROW
            (
                *fFormatter << XMLFormatter::NoEscapes << gStartComment
                            << nodeValue << gEndComment;
            )
            break;
        }

    case DOMNode::DOCUMENT_TYPE_NODE:  // Not to be shown to Filter
        {
            const DOMDocumentType *doctype = (const DOMDocumentType *)nodeToWrite;

            fFormatter->setEscapeFlags(XMLFormatter::NoEscapes);

            printNewLine();
            printIndent(level);

            TRY_CATCH_THROW
            (
                *fFormatter << gStartDoctype << nodeName;

                const XMLCh  *id = doctype->getPublicId();
                if (id && *id)
                {
                    *fFormatter << chSpace << gPublic << id << chDoubleQuote;

                    id = doctype->getSystemId();
                    if (id && *id)
                    {
                        *fFormatter << chSpace << chDoubleQuote << id << chDoubleQuote;
                    }
                    else
                    {
                        //
                        // 4.2.2 External Entities
                        // [Definition: If the entity is not internal,
                        //           it is an external entity, declared as follows:]
                        // External Entity Declaration
                        // [75] ExternalID ::= 'SYSTEM' S SystemLiteral
                        //                   | 'PUBLIC' S PubidLiteral S SystemLiteral
                        //
                        reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, XMLDOMMsg::Writer_NotRecognizedType);
                        // systemLiteral not found
                    }
                }
                else
                {
                    id = doctype->getSystemId();
                    if (id && *id)
                    {
                        *fFormatter << chSpace << gSystem << id << chDoubleQuote;
                    }
                }

                id = doctype->getInternalSubset();
                if (id && *id)
                {
                    *fFormatter << chSpace << chOpenSquare << id << chCloseSquare;
                }

                *fFormatter << chCloseAngle;
            ) // end of TRY_CATCH_THROW

            break;
        }

    case DOMNode::ENTITY_NODE:  // Not to be shown to Filter
        {
            //
            // REVISIT: how does the feature "entities" impact
            // entity node?
            //
            printNewLine();
            printIndent(level);

            fFormatter->setEscapeFlags(XMLFormatter::NoEscapes);
            *fFormatter << gStartEntity    << nodeName;

            const XMLCh * id = ((const DOMEntity*)nodeToWrite)->getPublicId();
            if (id)
                *fFormatter << gPublic << id << chDoubleQuote;

            id = ((const DOMEntity*)nodeToWrite)->getSystemId();
            if (id)
                *fFormatter << gSystem << id << chDoubleQuote;

            id = ((const DOMEntity*)nodeToWrite)->getNotationName();
            if (id)
                *fFormatter << gNotation << id << chDoubleQuote;

            *fFormatter << chCloseAngle;

            break;
        }

    default:
        /***
            This is an implementation specific behaviour, we abort if a user derived class has not dealt with
            this node type.
         ***/
        {
            if(!customNodeSerialize(nodeToWrite, level)) {
                reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, XMLDOMMsg::Writer_NotRecognizedType);
                // UnreognizedNodeType;
            }
        }

        break;
    }

}