/*
* Copyright (c) 2002-2006 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:        Class implements XML base fragment using libxml2 classes
*
*/








// INCLUDE FILES
#include <flogger.h>
#include <utf.h>
#include <s32mem.h>
#include "SenFragmentBase.h"
#include "SenParser.h"
#include "wslibxml2utils.h"

#include <SenXmlConstants.h>

#include <xml/attribute.h>               // needed for RAttributeArray
#include <xml/parserfeature.h>           // for TParserFeature enumeration
#include <xmlengserializationoptions.h> // for TSerializationOptions
#include <xmlengbinarycontainer.h>
#include <xmlengnodelist.h>


typedef unsigned char xmlChar; // from "libxml/Libxml2_xmlstring.h"

using namespace Xml;

// ***************************************************************************
// Fragment class state constants are as following (declared in subclasses):
// KSenStateNotSet                  = -1;
// KSenStateIgnore                  =  0; // even ones ignore(0),
// KSenStateSave                    =  1; // and odd ones save(1)
// KSenStateResume                  =  2;
// KStateParsingFramework           =  4;
// KStateParsingSoapFault           =  5;  // odd, save
// KStateParsingServiceDescription  =  6;
// KStateParsingResourceOffering    =  11; // odd, save
// KStateParsingCredentials         =  12;
// KStateParsingService             =  13; // odd state, saves content
// KStateParsingPwTransforms        =  14;
// KStateParsingSoapHeader          =  20; // ignore state (even num)
// KStateParsingSoapBody            =  40; // ignore state (even num)
// KStateParsingSingleCredential    =  122;
// KStateParsingProviderPolicy      =  1222;

namespace
    {
    const TInt KFlatBufSize = 128;
    _LIT(KSenFragmentPanic, "SenFragment");
    
    TBool EncodeXmlEscapesL( const TDesC8& aOriginal, HBufC8*& aEncoded )
        {
        TBool retVal = EFalse;
        delete aEncoded;
        aEncoded = NULL;
    
        if (aOriginal == KNullDesC8)
            {
            return retVal;
            }
        TPtrC8 tokens[] =
            {
            KSenEscapedAmp(),
            KSenEscapedApos(),
            KSenEscapedDblQuot(),
            KSenEscapedGt(),
            KSenEscapedLt()  
            };
        TText16 tokenChars[] =
            {
            '&',
            '\'',
            '\"',
            '>',
            '<'
            };
        
        // Replace escaped characters, if any
        for (TInt i = 0; i < aOriginal.Length(); i++)
            {
            TBool foundChar = EFalse;
            //for (TInt j = 0; j < (sizeof(tokenChars) / sizeof(TText16)); j++)
            for (TInt j = 0; j < 5; j++)
                {
                if (aOriginal[i] == tokenChars[j])
                    {
                    if ( !aEncoded )
                        {
                        aEncoded =
                            HBufC8::NewL(aOriginal.Length() * KSenMaxXmlEscapedLength);
                        aEncoded->Des().Append(aOriginal.Left(i));
                        }
                    foundChar = ETrue;
                    aEncoded->Des().Append(tokens[j]);
                    retVal = ETrue; // indicate, that encoding was done
                    break;
                    }
                }
            if (!foundChar)
                {
                if (aEncoded)
                    {
                    
                    aEncoded->Des().Append(aOriginal[i]);
                    }
                }
            }
        return retVal;
        }
    }

EXPORT_C CSenFragmentBase* CSenFragmentBase::NewL(const TXmlEngElement& aElement)
    {
    CSenFragmentBase* pNew = new (ELeave) CSenFragmentBase;
    CleanupStack::PushL(pNew);
    pNew->BaseConstructL(aElement);
    CleanupStack::Pop(pNew);
    return pNew;
    }

EXPORT_C CSenFragmentBase* CSenFragmentBase::NewL(const TDesC8& aLocalName)
    {
    CSenFragmentBase* pNew = new (ELeave) CSenFragmentBase;
    CleanupStack::PushL(pNew);
    pNew->BaseConstructL(aLocalName);
    CleanupStack::Pop(pNew);
    return pNew;
    }

EXPORT_C CSenFragmentBase* CSenFragmentBase::NewL(const TDesC8& aNsUri,
                                                  const TDesC8& aLocalName
    )
    {
    CSenFragmentBase* pNew = new (ELeave) CSenFragmentBase;
    CleanupStack::PushL(pNew);
    pNew->BaseConstructL(aNsUri, aLocalName);
    CleanupStack::Pop(pNew);
    return pNew;
    }

EXPORT_C CSenFragmentBase* CSenFragmentBase::NewL(const TDesC8& aNsUri,
                                                  const TDesC8& aLocalName,
                                                  const TDesC8& aPrefix,
                                                  const RAttributeArray& aAttrs
    )
    {
    CSenFragmentBase* pNew = new (ELeave) CSenFragmentBase;
    CleanupStack::PushL(pNew);
    pNew->BaseConstructL(aNsUri, aLocalName, aPrefix, aAttrs);
    CleanupStack::Pop(pNew);
    return pNew;
    }

EXPORT_C CSenFragmentBase* CSenFragmentBase::NewL(const TDesC8& aNsUri,
                                                  const TDesC8& aLocalName,
                                                  const TDesC8& aPrefix,
                                                  const RAttributeArray& aAttrs,
                                                  TXmlEngElement& aParent
    )
    {
    CSenFragmentBase* pNew = new (ELeave) CSenFragmentBase;
    CleanupStack::PushL(pNew);
    pNew->BaseConstructL(aNsUri, aLocalName, aPrefix, aAttrs, aParent);
    CleanupStack::Pop(pNew);
    return pNew;
    }

EXPORT_C CSenFragmentBase* CSenFragmentBase::NewL(const TDesC8& aNsUri,
                                                  const TDesC8& aLocalName,
                                                  const TDesC8& aPrefix,
                                                  const RAttributeArray& aAttrs,
                                                  TXmlEngElement& aParent,
                                                  RSenDocument& aOwnerDocument
    )
    {
    CSenFragmentBase* pNew = new (ELeave) CSenFragmentBase;
    CleanupStack::PushL(pNew);
    pNew->BaseConstructL(aNsUri, aLocalName, aPrefix, aAttrs, aParent,
                         aOwnerDocument);
    CleanupStack::Pop(pNew);
    return pNew;
    }

EXPORT_C CSenFragmentBase* CSenFragmentBase::NewL(const TDesC8& aNsUri,
                                                  const TDesC8& aLocalName,
                                                  const TDesC8& aPrefix
    )
    {
    CSenFragmentBase* pNew = new (ELeave) CSenFragmentBase;
    CleanupStack::PushL(pNew);
    pNew->BaseConstructL(aNsUri, aLocalName, aPrefix);
    CleanupStack::Pop(pNew);
    return pNew;
    }
    
EXPORT_C CSenFragmentBase* CSenFragmentBase::NewL(TXmlEngElement& aRootElement,
                                                  RSenDocument& aOwnerDocument)
    {
    CSenFragmentBase* pNew = new (ELeave) CSenFragmentBase;
    CleanupStack::PushL(pNew);
    pNew->BaseConstructL(aRootElement, aOwnerDocument);
    CleanupStack::Pop(pNew);
    return pNew;
    }

EXPORT_C CSenFragmentBase::~CSenFragmentBase()
    {
    if ( ipNamespaceArray )
        {
        ipNamespaceArray->ResetAndDestroy();
        delete ipNamespaceArray;
        }
    iDocument.Close();
    if ( ipContentBuf )
    	{
                
        delete ipContentBuf;
        ipContentBuf = NULL;
        
        delete ipContentWriteStream;
        ipContentWriteStream = NULL;
        }
        
     if ( ipDelegate )
        {
        delete ipDelegate;
        ipDelegate = NULL;
        }   
    }

EXPORT_C CSenFragmentBase::CSenFragmentBase()
:   iState(KSenStateIgnore),
    ipParser(NULL),
    ipOwner(NULL),
    ipDelegate(NULL)
    {
    }

EXPORT_C void CSenFragmentBase::BaseConstructL(const TXmlEngElement& aSrc)
    {
    iElement = aSrc.CopyL();
    iDocument = RSenDocument::NewL();
    iDocument.SetDocumentElement(iElement);
    }

EXPORT_C void CSenFragmentBase::BaseConstructL(const TDesC8& aLocalName)
    {
    iDocument = RSenDocument::NewL();
    if ( aLocalName != KNullDesC8 )
        {
        iDocument.CreateDocumentElementL(aLocalName);
        iElement = iDocument.DocumentElement();
        }
    }

EXPORT_C void CSenFragmentBase::BaseConstructL(const TDesC8& aNsUri,
                                               const TDesC8& aLocalName
    )
    {
    iDocument = RSenDocument::NewL();
    iDocument.CreateDocumentElementL(aLocalName, aNsUri);
    iElement = iDocument.DocumentElement();
    }

EXPORT_C void CSenFragmentBase::BaseConstructL(const TDesC8& aNsUri,
                                               const TDesC8& aLocalName,
                                               const TDesC8& aPrefix,
                                               const RAttributeArray& aAttrs
    )
    {
    iDocument = RSenDocument::NewL();
    if (aPrefix == KNullDesC8)
        {
        iDocument.CreateDocumentElementL(aLocalName, aNsUri);
        }
    else
        {
        iDocument.CreateDocumentElementL(aLocalName, aNsUri, aPrefix);
        }

    iElement = iDocument.DocumentElement();
    AddAttributesL(aAttrs);
    }

EXPORT_C void CSenFragmentBase::BaseConstructL(
    const TDesC8& aNsUri,
    const TDesC8& aLocalName,
    const TDesC8& aPrefix,
    const RAttributeArray& aAttributes,
    TXmlEngElement& aParent
    )
    {
    iDocument = RSenDocument::NewL();
    iElement = aParent.AddNewElementL(aLocalName);

    if (aNsUri != KNullDesC8 || aPrefix != KNullDesC8)
        {
        if (aPrefix == KNullDesC8)
            {
            // Check if namespace declaration for the root tag
            // is already defined in parent element.
            TXmlEngNamespace ns = aParent.LookupNamespaceByUriL(aNsUri);
            if ( ns.IsNull() )
                {
                // Namespace declaration will be added to iElement
                iElement.AddNamespaceDeclarationL(aNsUri, KNullDesC8);
                }

            WsXmlUtils domUtils;       
            domUtils.XmlEngRenameElementL(iElement, aLocalName, aNsUri, KNullDesC8);
            }
        else
            {
            // Check if namespace declaration for the root tag
            // is already defined in parent element.
            TXmlEngNamespace ns = aParent.LookupNamespaceByUriL(aNsUri);
            if ( ns.IsNull() )
                {
                // Namespace declaration will be added to iElement
                iElement.AddNamespaceDeclarationL(aNsUri, aPrefix);
                }

            WsXmlUtils domUtils;
            domUtils.XmlEngRenameElementL(iElement, aLocalName, aNsUri, aPrefix);
            }
        }
    
    aParent.AppendChildL(iElement);

    AddAttributesL(aAttributes);
    }

EXPORT_C void CSenFragmentBase::BaseConstructL(
    const TDesC8& aNsUri,
    const TDesC8& aLocalName,
    const TDesC8& aPrefix,
    const RAttributeArray& aAttributes,
    TXmlEngElement& aParent,
    RSenDocument& aOwnerDocument
    )
    {
    iDocument = aOwnerDocument.Copy();
    iElement = aParent.AddNewElementL(aLocalName);
    
    if ( aNsUri != KNullDesC8 || aPrefix != KNullDesC8 )
        {
        if ( aPrefix == KNullDesC8 )
            {
            // Check if namespace declaration for the root tag
            // is already defined in parent element.
            TXmlEngNamespace ns = aParent.LookupNamespaceByUriL(aNsUri);
            if ( ns.IsNull() )
                {
                // Namespace declaration will be added to iElement
                iElement.AddNamespaceDeclarationL(aNsUri, KNullDesC8);
                }

            WsXmlUtils domUtils;
            domUtils.XmlEngRenameElementL(iElement, aLocalName, aNsUri, KNullDesC8);
            }
        else
            {
            // Check if namespace declaration for the root tag
            // is already defined in parent element.
            TXmlEngNamespace ns = aParent.LookupNamespaceByUriL(aNsUri);
            if ( ns.IsNull() )
                {
                // Namespace declaration will be added to iElement
                iElement.AddNamespaceDeclarationL(aNsUri, aPrefix);
                }
            WsXmlUtils domUtils;
            domUtils.XmlEngRenameElementL(iElement, aLocalName, aNsUri, aPrefix);
            }
        }
    
    aParent.AppendChildL(iElement);

    AddAttributesL(aAttributes);
    }

EXPORT_C void CSenFragmentBase::BaseConstructL(const TDesC8& aNsUri,
                                               const TDesC8& aLocalName,
                                               const TDesC8& aPrefix
    )
    {
    iDocument = RSenDocument::NewL();
    if ( aNsUri == KNullDesC8 && aPrefix == KNullDesC8 )
        {
        iDocument.CreateDocumentElementL(aLocalName);
        }
    else
        {
        if ( aPrefix == KNullDesC8 )
            {
            iDocument.CreateDocumentElementL(aLocalName, aNsUri, KNullDesC8);
            }
        else
            {
            iDocument.CreateDocumentElementL(aLocalName, aNsUri, aPrefix);
            }
        }
    iElement = iDocument.DocumentElement();
    }
    
EXPORT_C void CSenFragmentBase::BaseConstructL(TXmlEngElement& aRootElement,
                                               RSenDocument& aOwnerDocument)
    {
    iDocument = aOwnerDocument.Copy();
    iElement = aRootElement;
    }

EXPORT_C void CSenFragmentBase::AddNamespacesL()
    {
    if (ipParser)
        {
        if ( ipParser->IsFeatureEnabled(EReportNamespaceMapping) )
            {
            // Add namespaces, if any
            if ( ipNamespaceArray )
                {
                TInt count = ipNamespaceArray->Count();
                for (TInt i=0; i < count; i++)
                    {
                    CSenNamespaceData* pNamespace = (*ipNamespaceArray)[i];
                    TXmlEngNamespace ns =
                                AsElementL().LookupNamespaceByUriL(*pNamespace->ipNamespaceUri);
                    if ( ns.IsNull() )
                        {
                        if (pNamespace->ipPrefix == NULL)
                            {
                            AsElementL().AddNamespaceDeclarationL(*pNamespace->ipNamespaceUri,
                                                                  KNullDesC8);
                            }
                        else
                            {
                            AsElementL().AddNamespaceDeclarationL(*pNamespace->ipNamespaceUri,
                                                                  *pNamespace->ipPrefix);
                            }
                        }
                    }
                ipNamespaceArray->ResetAndDestroy();
                }
            }
        }
    }
    
EXPORT_C void CSenFragmentBase::AddAttributesToElementL(TXmlEngElement aElement,
                                               const RAttributeArray& apAttrs)
    {
    TInt count(apAttrs.Count());

    for(TInt i=0; i<count; i++)
        {
        TPtrC8 localName = apAttrs[i].Attribute().LocalName().DesC();
        TPtrC8 value = apAttrs[i].Value().DesC();

        if (apAttrs[i].Attribute().Uri().DesC() == KNullDesC8)
            {
            aElement.AddNewAttributeL(localName, value);
            }
        else
            {
            TPtrC8 namespaceUri = apAttrs[i].Attribute().Uri().DesC();
            TPtrC8 prefix(KNullDesC8);
            if ( apAttrs[i].Attribute().Prefix().DesC() != KNullDesC8 )
                {
                prefix.Set(apAttrs[i].Attribute().Prefix().DesC());
                }
                
            TXmlEngNamespace ns = aElement.LookupNamespaceByUriL(namespaceUri);
            if ( ns.NotNull() )
                {
                if (ns.Prefix() == KNullDesC8 && prefix == KNullDesC8)
                    {
                    aElement.AddNewAttributeWithNsL(localName, value, namespaceUri);
                    }
                else if ( ns.Prefix() == prefix )
                    {
                    aElement.AddNewAttributeL(localName, value, ns);
                    }
                else
                    {
                    aElement.AddNewAttributeL(localName, value, namespaceUri, prefix);
                    }
                }
            else
                {
                if ( prefix == KNullDesC8 )
                    {
                    aElement.AddNamespaceDeclarationL(namespaceUri, KNullDesC8);
                    aElement.AddNewAttributeWithNsL(localName, value, namespaceUri);
                    }
                else
                    {
                    aElement.AddNewAttributeL(localName, value, namespaceUri, prefix);
                    }
                }
            }
        }
    }

EXPORT_C void CSenFragmentBase::AddAttributesL(const RAttributeArray& apAttrs)
    {
    AddAttributesToElementL(AsElementL(), apAttrs);
    }

EXPORT_C RSenDocument& CSenFragmentBase::AsDocumentL()
    {
    return iDocument;
    }

EXPORT_C TXmlEngElement CSenFragmentBase::AsElementL()
    {
    __ASSERT_ALWAYS(iElement.NotNull(), User::Panic(KSenFragmentPanic, EFragmentElementNotInitialized));
    
    return iElement;
    }
    
void CSenFragmentBase::RenameL(const TDesC8& aLocalName, const TDesC8& aPrefix, const TDesC8& aNamespace)
    {
    WsXmlUtils domUtils;       
    domUtils.XmlEngRenameElementL(AsElementL(), aLocalName, aNamespace, aPrefix); // Note that in TElement the *prefix* is the last arg(!)
    }

void CSenFragmentBase::RenameL(const TDesC8& aLocalName, const TDesC8& aNamespace)
    {
    WsXmlUtils domUtils;       
    domUtils.XmlEngRenameElementL(AsElementL(), aLocalName, aNamespace, KNullDesC8); // Note that in TElement the *prefix* is the last arg(!)
    }
    
void CSenFragmentBase::RenameLocalNameL(const TDesC8& aLocalName)
    {
    WsXmlUtils domUtils;       
    domUtils.XmlEngRenameElementL(AsElementL(), aLocalName, KNullDesC8, KNullDesC8); // Note that in TElement the *prefix* is the last arg(!)
    }

void CSenFragmentBase::RenameNamespaceL(const TDesC8& aNamespace)
    {
    WsXmlUtils domUtils;       
    domUtils.XmlEngRenameElementL(AsElementL(), KNullDesC8, aNamespace, KNullDesC8); // Note that in TElement the *prefix* is the last arg(!)
    }
    
void CSenFragmentBase::RenameNamespaceL(const TDesC8& aPrefix, const TDesC8& aNamespace)
    {
    WsXmlUtils domUtils;       
    domUtils.XmlEngRenameElementL(AsElementL(), KNullDesC8, aNamespace, aPrefix); // Note that in TElement the *prefix* is the last arg(!)
    }
    
void CSenFragmentBase::RenamePrefixL(const TDesC8& aPrefix)
    {
    WsXmlUtils domUtils;       
    domUtils.XmlEngRenameElementL(AsElementL(), KNullDesC8, KNullDesC8, aPrefix); // Note that in TElement the *prefix* is the last arg(!)
    }
    
EXPORT_C TXmlEngElement CSenFragmentBase::ExtractElement()
    {
    TXmlEngElement element = iDocument.DocumentElement();

    if ( element.IsSameNode(iElement) )
        {
        // Unlink only when element is root element of this document.
        //
        // This fragment maybe delegate and element is still part
        // of other Fragment's DOM Tree.
        iElement.Unlink();
        }

    TXmlEngElement retElement = iElement;        
    TXmlEngElement nullElement;
    iElement = nullElement;
    
    return retElement;
    }

EXPORT_C void CSenFragmentBase::SetParser(CSenParser& aParser)
    {
    ipParser = &aParser;
    }

EXPORT_C void CSenFragmentBase::OnDelegateParsingL(CSenFragmentBase& aDelegate)
    {
    // Delegate parsing to a new Fragment, until we encounter 
    // the end of an element with the given qualified name
    aDelegate.SetOwner(*this);
    aDelegate.ipParser = ipParser;
    aDelegate.StartSavingContent();
    SetContentHandler(aDelegate);
    }

EXPORT_C void CSenFragmentBase::OnDelegateParsingL(const RTagInfo& aElement, 
                                                   const RAttributeArray& aAttributes, 
                                                   TInt /*aErrorCode*/)
    {
    // Delegate parsing to a new Fragment, until we encounter the end of an
    // element with the given qualified name
    const TPtrC8 saxLocalName   = aElement.LocalName().DesC();
    const TPtrC8 saxNsUri       = aElement.Uri().DesC();
    const TPtrC8 saxPrefix      = aElement.Prefix().DesC();

    TXmlEngElement element = AsElementL();
    RSenDocument document = AsDocumentL();


    __ASSERT_ALWAYS(
        ipDelegate == NULL,
        User::Panic(KSenFragmentPanic, EDelegatedFragmentAlreadySet)
        );
    ipDelegate = CSenFragmentBase::NewL(saxNsUri, 
                                        saxLocalName, 
                                        saxPrefix, 
                                        aAttributes, 
                                        element, 
                                        document);

    OnDelegateParsingL(*ipDelegate);
    }

EXPORT_C void CSenFragmentBase::StartSavingContent()
    {
    iState = KSenStateSave;
    }

EXPORT_C void CSenFragmentBase::SetOwner(CSenFragmentBase& aFragment)
    {
    ipOwner = &aFragment;
    }

EXPORT_C void CSenFragmentBase::OnResumeParsingFromL(const RTagInfo& aElement, TInt aErrorCode)
    {
    SetContentHandler(*this);
    
    // Destroy delegate
    if ( ipDelegate )
        {
        HBufC8* pAsXml = ipDelegate->AsXmlL();
        CleanupStack::PushL(pAsXml);
                
        delete ipDelegate; // free memory
        ipDelegate = NULL;
        
        if ( !ipContentBuf )
            {
            ipContentBuf = CBufFlat::NewL(KFlatBufSize);
            ipContentWriteStream = new (ELeave) RBufWriteStream;
            ipContentWriteStream->Open(*ipContentBuf);
            }
        ipContentWriteStream->WriteL(*pAsXml);
        
        CleanupStack::PopAndDestroy(pAsXml);
        }
    
    TInt currentState = KSenStateNotSet; // == -1
    if ( iElement.NotNull() )
        {
        const TPtrC8 saxLocalName   = aElement.LocalName().DesC();
        const TPtrC8 saxNsUri       = aElement.Uri().DesC();
        TPtrC8 localName            = iElement.Name();
        TPtrC8 nsUri                = iElement.NamespaceUri();
    
        if(localName == saxLocalName  && nsUri == saxNsUri)
            {
            currentState = iState;
            // Before calling EndElementL, which may execute
            // unpredictable amount of code in subclasses, the
            // the state must be set to "ignore"
            iState = KSenStateResume;
            }
        }
    
    OnEndElementL(aElement, aErrorCode);
    // now check if current state was to be preserved
    if(currentState!=KSenStateNotSet) // IOP
        {
        // restore the state preserved prior to
        // "set ignore for endelement" -case
        iState = currentState;
        }
    }

EXPORT_C void CSenFragmentBase::OnStartElementL(const RTagInfo& aElement, 
                                                const RAttributeArray& aAttributes, 
                                                TInt aErrorCode) 
    {
    const TPtrC8 saxLocalName   = aElement.LocalName().DesC();
    const TPtrC8 saxNsUri       = aElement.Uri().DesC();
    const TPtrC8 saxPrefix      = aElement.Prefix().DesC();
    
    if ( iElement.IsNull() )
        {
        if ( saxNsUri == KNullDesC8 && saxPrefix == KNullDesC8 )
            {
            iDocument.CreateDocumentElementL(saxLocalName);
            }
        else
            {
            if ( saxPrefix == KNullDesC8 )
                {
                iDocument.CreateDocumentElementL(saxLocalName,
                                                 saxNsUri,
                                                 KNullDesC8);
                }
            else
                {
                iDocument.CreateDocumentElementL(saxLocalName,
                                                 saxNsUri,
                                                 saxPrefix);
                }
            }
        iElement = iDocument.DocumentElement();        
        }    
    
    TXmlEngElement element = AsElementL();
    
    TPtrC8 localName =  element.Name();
    TPtrC8 nsUri(KNullDesC8);
    if (element.NamespaceUri() != KNullDesC8)
        {
        nsUri.Set(element.NamespaceUri());
        }
    
    if(iState == KSenStateIgnore)
        {
        if(localName == saxLocalName && nsUri == saxNsUri) 
            {
            iState = KSenStateSave;
            AddNamespacesL();
            AddAttributesL(aAttributes);
            }
        }
    else if((iState & KSenStateSave) == KSenStateSave)
        {
        if(localName == saxLocalName && nsUri == saxNsUri)
            {
            // start a new BaseFragment otherwise we loose
            // track of nested elements with the same name
            OnDelegateParsingL(aElement, aAttributes, aErrorCode);
            }
        else
            {
            OnWriteStartElementL(aElement, aAttributes);
            }
        }
    }

EXPORT_C void CSenFragmentBase::OnEndElementL(const RTagInfo& aElement, TInt aErrorCode)
    {
    const TPtrC8 saxLocalName   = aElement.LocalName().DesC();
    const TPtrC8 saxNsUri       = aElement.Uri().DesC();
    const TPtrC8 saxPrefix      = aElement.Prefix().DesC();

    TXmlEngElement element = AsElementL();

    TPtrC8 localName =  element.Name();
    TPtrC8 nsUri(KNullDesC8);
    if (element.NamespaceUri() != KNullDesC8)
        {
        nsUri.Set(element.NamespaceUri());
        }

    if(localName == saxLocalName && nsUri == saxNsUri)
        {
        if(iState != KSenStateResume && ipOwner)
            {
            if ( ipContentBuf )
                {
                SetContentL(ipContentBuf->Ptr(0));
            
                delete ipContentBuf;
                ipContentBuf = NULL;
                delete ipContentWriteStream;
                ipContentWriteStream = NULL;
                }

            ipOwner->OnResumeParsingFromL(aElement, aErrorCode);
            return; // This is mandatory, since ResumeParsingFromL 
                    // de-allocates delegate fragment!
            }
        iState = KSenStateIgnore;
        }
    if((iState & KSenStateSave) == KSenStateSave)
        {
        OnWriteEndElementL(aElement);
        }
    }

EXPORT_C void CSenFragmentBase::OnContentL(const TDesC8& aBytes, TInt /*aErrorCode*/)
    {
    if((iState & KSenStateSave) == KSenStateSave)
        {
        if ( !ipContentBuf )
            {
            ipContentBuf = CBufFlat::NewL(KFlatBufSize);
            ipContentWriteStream = new (ELeave) RBufWriteStream;
            ipContentWriteStream->Open( *ipContentBuf );
            }   
        HBufC8* reEncoded = NULL;
        TBool contentIncludesEncodedChars = EncodeXmlEscapesL( aBytes, reEncoded);
        if ( contentIncludesEncodedChars )
            {
            CleanupStack::PushL( reEncoded );
            ipContentWriteStream->WriteL( *reEncoded );
            CleanupStack::PopAndDestroy( reEncoded  );
            }
        else
            {
            ipContentWriteStream->WriteL( aBytes );
            }
        }
    }
    
EXPORT_C void CSenFragmentBase::OnStartDocumentL( const RDocumentParameters& /*aDocParam*/,
                                                  TInt /*aErrorCode*/ )
    {
    if ( !ipContentBuf )
        {
        ipContentBuf = CBufFlat::NewL(KFlatBufSize);
        ipContentWriteStream = new (ELeave) RBufWriteStream;
        ipContentWriteStream->Open(*ipContentBuf);
        }
    }

EXPORT_C void CSenFragmentBase::OnEndDocumentL(TInt /*aErrorCode*/)
    {
    if ( ipNamespaceArray)
        {
        ipNamespaceArray->ResetAndDestroy();
        delete ipNamespaceArray;
        ipNamespaceArray = NULL;
        }
    
    if ( ipContentBuf )
        {
        if ( ipContentBuf->Ptr(0).Length() > 0 )
            {
            SetContentL(ipContentBuf->Ptr(0));
            }

        delete ipContentBuf;
        ipContentBuf = NULL;
        delete ipContentWriteStream;
        ipContentWriteStream = NULL;
        }
    }

EXPORT_C void CSenFragmentBase::OnStartPrefixMappingL(
                                    const RString& aPrefix,
                                    const RString& aUri,
                                    TInt /*aErrorCode*/)
    {
    if ( !ipNamespaceArray )
        {
        ipNamespaceArray = new (ELeave) RPointerArray<CSenNamespaceData>;
        }

    CSenNamespaceData* pNamespaceData = new (ELeave) CSenNamespaceData;
    CleanupStack::PushL(pNamespaceData);
    pNamespaceData->ipNamespaceUri  = aUri.DesC().AllocL();
    if (aPrefix.DesC() != KNullDesC8)
        {
        pNamespaceData->ipPrefix    = aPrefix.DesC().AllocL();
        }
    User::LeaveIfError(ipNamespaceArray->Append(pNamespaceData));
    CleanupStack::Pop(pNamespaceData);
    }

EXPORT_C void CSenFragmentBase::OnEndPrefixMappingL(
                                    const RString& /*aPrefix*/,
                                    TInt /*aErrorCode*/)
    {
    }

EXPORT_C void CSenFragmentBase::OnIgnorableWhiteSpaceL(
                                    const TDesC8& /*aBytes*/,
                                    TInt /*aErrorCode*/)
    {
    }

EXPORT_C void CSenFragmentBase::OnSkippedEntityL(
                                    const RString& /*aName*/,
                                    TInt /*aErrorCode*/)
    {
    }

EXPORT_C void CSenFragmentBase::OnProcessingInstructionL(
                                    const TDesC8& /*aTarget*/,
                                    const TDesC8& /*aData*/,
                                    TInt /*aErrorCode*/)
    {
    }

EXPORT_C void CSenFragmentBase::OnError(TInt /*aErrorCode*/)
    {
    }

EXPORT_C TAny* CSenFragmentBase::GetExtendedInterface(const TInt32 /*aUid*/)
    {
    return NULL;
    }    


EXPORT_C void CSenFragmentBase::ResetContentL()
    {
    TXmlEngElement element = AsElementL();
    element.RemoveChildren();
    }

EXPORT_C TPtrC8 CSenFragmentBase::ContentL()
    {
    TXmlEngElement element = AsElementL();
    return element.Text();
    }


EXPORT_C HBufC* CSenFragmentBase::AsXmlUnicodeL()
    {
    HBufC8* pAsXml = AsXmlL();
    CleanupStack::PushL(pAsXml);
    HBufC16* pBuf = HBufC16::NewL(2 * pAsXml->Length());
    CleanupStack::PushL(pBuf);
    TPtr16 des = pBuf->Des();
    TInt ret = CnvUtfConverter::ConvertToUnicodeFromUtf8(des, *pAsXml);
    User::LeaveIfError(ret);
    CleanupStack::Pop(pBuf);
    CleanupStack::PopAndDestroy(pAsXml);
    return pBuf;
    }

EXPORT_C HBufC8* CSenFragmentBase::AsXmlL()
    {
    TXmlEngElement element = AsElementL();
    
    TUint optionFlags = 0;
    // Omit following declarations from the beginning of XML Document:
    // <?xml version=\"1.0\...
    //   encoding="..."
    //   standalone="..."
    // ?>
    optionFlags = optionFlags | TXmlEngSerializationOptions::KOptionOmitXMLDeclaration;
    
    // Allow encoding declaration (if KOptionOmitXMLDeclaration is _not_ set)
    //optionFlags = optionFlags | TSerializationOptions::KOptionEncoding;
    
    // Allow standalone declaration (if KOptionOmitXMLDeclaration is _not_ set)
    //optionFlags = optionFlags | TSerializationOptions::KOptionStandalone;

    TXmlEngSerializationOptions options(optionFlags);

    RBuf8 asXml;
    iDocument.SaveL(asXml, element, options);
    CleanupClosePushL(asXml);
    HBufC8* pAsXml = asXml.AllocL();
    CleanupStack::PopAndDestroy(&asXml);

    return pAsXml;
    }
    

EXPORT_C void CSenFragmentBase::WriteAsXMLToL(RWriteStream& aWs)
    {
    HBufC8* pAsXml = AsXmlL();
    CleanupStack::PushL(pAsXml);
    aWs.WriteL(*pAsXml);
    CleanupStack::PopAndDestroy(pAsXml);
    }

EXPORT_C TPtrC8 CSenFragmentBase::ContentOf(const TDesC8& aLocalName)
    {
    TInt err( KErrNone );
    RXmlEngNodeList<TXmlEngElement> list;
    TRAP(   
        err, 
        TXmlEngElement element = AsElementL(); 
        element.GetElementsByTagNameL(list, aLocalName);
        )
    if ( !err && list.Count() > 0 )
        {
        TXmlEngElement firstElement = list.Next();
        return firstElement.Text();
        }
    return KNullDesC8();
    }

EXPORT_C TXmlEngElement CSenFragmentBase::SetContentOfL(const TDesC8& aLocalName,
                                                      const TDesC8& aContent)
    {
    TXmlEngElement element = AsElementL();
    RXmlEngNodeList<TXmlEngElement> list;
    CleanupClosePushL(list);
    
    element.GetElementsByTagNameL(list, aLocalName);
        
    if ( list.Count() > 0 )
        {
        TXmlEngElement firstElement = list.Next();
        firstElement.SetTextNoEncL(aContent);
        return firstElement;
        }
    CleanupStack::PopAndDestroy(&list);

    TXmlEngElement newElement = element.AddNewElementL(aLocalName);
    newElement.SetTextNoEncL(aContent);
    return newElement;
    }

EXPORT_C void CSenFragmentBase::OnWriteStartElementL(const RTagInfo& aElement,  
                                                     const RAttributeArray& aAttributes)
    {
    const TPtrC8 saxLocalName   = aElement.LocalName().DesC();
    const TPtrC8 saxNsUri       = aElement.Uri().DesC();
    const TPtrC8 saxPrefix      = aElement.Prefix().DesC();
    
    if ( !ipContentBuf )
        {
        ipContentBuf = CBufFlat::NewL(KFlatBufSize);
        ipContentWriteStream = new (ELeave) RBufWriteStream;
        ipContentWriteStream->Open(*ipContentBuf);
        }
    
    ipContentWriteStream->WriteL(KSenLessThan);
    if (saxPrefix != KNullDesC8)
        {
        ipContentWriteStream->WriteL(saxPrefix);
        ipContentWriteStream->WriteL(KSenColon);
        }
    ipContentWriteStream->WriteL(saxLocalName);

    TInt startPoint(0);
    if ( !ipParser->IsFeatureEnabled(EReportNamespaceMapping) )
        {
        if ( !ipNamespaceArray)
            {
            ipNamespaceArray = new (ELeave) RPointerArray<CSenNamespaceData>;
            }

        // Collect namespace declaration from this element (if it's not
        // previously defined)
        TBool found(EFalse);
        if ( saxNsUri != KNullDesC8 )
            {
            // Check if element of this document has already handled
            // namespace definition.
            TXmlEngNamespace ns = AsElementL().LookupNamespaceByUriL(saxNsUri);
            if ( ns.NotNull() )
                {
                found = ETrue;
                }
            else
                {
                // Check if internal namespace array has already handled
                // namespace defintion. <= Means that one of the parent
                // elements (in flat content) has already namespace
                // definition we are dealing with.
                TInt jcount = ipNamespaceArray->Count();
                for (TInt j=0; j < jcount; j++)
                    {
                    CSenNamespaceData* pNamespace = (*ipNamespaceArray)[j];
                    if ( pNamespace->ipPrefix && *(pNamespace->ipPrefix) == saxPrefix )
                        {
                        if ( *pNamespace->ipNamespaceUri == saxNsUri )
                            {
                            found = ETrue;
                            break;
                            }
                        }
                    }
                }
            }

        startPoint = ipNamespaceArray->Count();
        if ( !found )
            {
            CSenNamespaceData* pNamespaceData = new (ELeave) CSenNamespaceData;
            CleanupStack::PushL(pNamespaceData);
            TInt retVal = ipNamespaceArray->Append(pNamespaceData);
            User::LeaveIfError(retVal);
            CleanupStack::Pop(pNamespaceData);
            if (retVal == KErrNone )
                {
                pNamespaceData->ipNamespaceUri  = saxNsUri.AllocL();
                pNamespaceData->ipPrefix        = saxPrefix.AllocL();
                pNamespaceData->ipLocalName     = saxLocalName.AllocL();
                }
            }
        
        // Collect new (not previously defined) namespaces from attributes
        TInt attCount(aAttributes.Count());
        for ( TInt i = 0; i < attCount; i++)
            {
            found = EFalse;
            TPtrC8 nsUri = aAttributes[i].Attribute().Uri().DesC();
            if ( nsUri != KNullDesC8 )
                {
                TPtrC8 nsPrefix = aAttributes[i].Attribute().Prefix().DesC();
                TBool found(EFalse);
                // Check if element of this document has already handled
                // namespace definition.
                TXmlEngNamespace ns = AsElementL().LookupNamespaceByUriL(nsUri);
                if ( ns.NotNull() )
                    {
                    found = ETrue;
                    }
                else
                    {
                    // Check if internal namespace array has already handled
                    // namespace defintion. <= Means that one of the parent
                    // elements (in flat content) has already namespace
                    // definition we are dealing with.
                    TInt jcount = ipNamespaceArray->Count();
                    for (TInt j=0; j < jcount; j++)
                        {
                        CSenNamespaceData* pNamespace = (*ipNamespaceArray)[j];
                        if ( pNamespace->ipPrefix && *(pNamespace->ipPrefix) == nsPrefix )
                            {
                            if ( *pNamespace->ipNamespaceUri == nsUri )
                                {
                                found = ETrue;
                                break;
                                }
                            }
                        }
                    }
                    
                // If namespace was not found
                // namespace will be added to internal array 
                if ( !found )
                    {
                    CSenNamespaceData* pNamespaceData
                                            = new (ELeave) CSenNamespaceData;
                    CleanupStack::PushL(pNamespaceData);
                    TInt retVal = ipNamespaceArray->Append(pNamespaceData);
                    User::LeaveIfError(retVal);
                    CleanupStack::Pop(pNamespaceData);
                    if (retVal == KErrNone )
                        {
                        pNamespaceData->ipNamespaceUri  = nsUri.AllocL();
                        pNamespaceData->ipPrefix        = nsPrefix.AllocL();
                        if ( startPoint == ipNamespaceArray->Count() )
                            {
                            pNamespaceData->ipLocalName = saxLocalName.AllocL();
                            }
                        }
                    }
                }
            }
        }
        
    // Write namespaces, if any
    if ( ipNamespaceArray )
        {
        TInt count = ipNamespaceArray->Count();
        for (TInt i=startPoint; i < count; i++)
            {
            CSenNamespaceData* pNamespace = (*ipNamespaceArray)[i];
            ipContentWriteStream->WriteL(KSenSpace);
            ipContentWriteStream->WriteL(KSenXmlns);
            if ( pNamespace->ipPrefix && *(pNamespace->ipPrefix) != KNullDesC8 )
                {
                ipContentWriteStream->WriteL(KSenColon);
                ipContentWriteStream->WriteL(*pNamespace->ipPrefix);
                }
            ipContentWriteStream->WriteL(KSenEqualsDblQuot);
            ipContentWriteStream->WriteL(*pNamespace->ipNamespaceUri);
            ipContentWriteStream->WriteL(KSenDblQuot);
            }
            
        if ( ipParser->IsFeatureEnabled(EReportNamespaceMapping) )
            {
            ipNamespaceArray->ResetAndDestroy();
            }
        }

    // Write attributes, if any
    TInt attCount(aAttributes.Count());
    for (TInt i = 0; i < attCount; i++)
        {
        TPtrC8 prefix   = aAttributes[i].Attribute().Prefix().DesC();
        TPtrC8 lAttName = aAttributes[i].Attribute().LocalName().DesC();
        TPtrC8 attValue = aAttributes[i].Value().DesC();

        ipContentWriteStream->WriteL(KSenSpace);
        if (prefix != KNullDesC8)
            {
            ipContentWriteStream->WriteL(prefix);
            ipContentWriteStream->WriteL(KSenColon);
            }
        ipContentWriteStream->WriteL(lAttName);

        ipContentWriteStream->WriteL(KSenEqualsDblQuot);
        ipContentWriteStream->WriteL(attValue);
        ipContentWriteStream->WriteL(KSenDblQuot);
        }

    ipContentWriteStream->WriteL(KSenGreaterThan);
    }

EXPORT_C void CSenFragmentBase::OnWriteEndElementL(const RTagInfo& aElement)
    {
    const TPtrC8 saxLocalName = aElement.LocalName().DesC();
    const TPtrC8 saxNsUri = aElement.Uri().DesC();
    const TPtrC8 saxPrefix = aElement.Prefix().DesC();

    if ( !ipContentBuf )
        {
        ipContentBuf = CBufFlat::NewL(KFlatBufSize);
        ipContentWriteStream = new (ELeave) RBufWriteStream;
        ipContentWriteStream->Open(*ipContentBuf);
        }
    
    if ( ipNamespaceArray && !ipParser->IsFeatureEnabled(EReportNamespaceMapping) )
        {
        TInt foundIndex(KErrNotFound);
        TInt jcount = ipNamespaceArray->Count();
        for (TInt j=jcount-1; j >= 0 ; j--)
            {
            CSenNamespaceData* pNamespace = (*ipNamespaceArray)[j];
            if ( pNamespace->ipLocalName != NULL )
                {
                if ( *pNamespace->ipLocalName == saxLocalName )
                    {
                    foundIndex = j;
                    }
                break;
                }
            }
        if ( foundIndex != KErrNotFound )
            {
            for (TInt j=foundIndex; j < jcount; j++)
                {
                delete (*ipNamespaceArray)[foundIndex];
                ipNamespaceArray->Remove(foundIndex);
                }
            }
        }

    // Check if EndTag should be written or not.
    // There is no need to write EndTag if
    // previous tag is StartTag for this element
    // and there is no content for the element.
    TBool writeEndTag = ETrue;        
    TInt size = ipContentBuf->Size();
    if ( size > 1 )
        {
        // Check if first character before this possible
        // EndTag is '>'
        if ( ipContentBuf->Ptr(size-1) == KSenGreaterThan )
            {
            // This element does not have content
            // There is possibility that EndTag is not needed
            TInt colon = KErrNotFound;
            TInt space = KErrNotFound;
            TBool insideDblQuot = EFalse;
            
            // Search backwards first '<'.
            // Search also first ':' and space which
            // are right after '<' (if those characters
            // can be found).
            // 
            // => Following situations are handled:
            // 1) <prefix:localname attr...>
            // 2) <prefix:localname>
            // 3) <localname>
            TInt i=size-2;
            TPtrC8 currentCharacter(KNullDesC8);
            for (; i > 0; i--)
                {
                currentCharacter.Set(ipContentBuf->Ptr(i).Left(1));
                
                if ( currentCharacter == KSenDblQuot ) 
                    {
                    if ( insideDblQuot )
                        {
                        insideDblQuot = EFalse;
                        }
                    else
                        {
                        insideDblQuot = ETrue;
                        }
                    }
                else if ( !insideDblQuot )
                    {
                    if ( currentCharacter == KSenSlash ) 
                        {
                        i = KErrNotFound;
                        break;
                        }
                    else if ( currentCharacter == KSenLessThan ) 
                        {
                        break;
                        }
                    else if ( currentCharacter == KSenColon )
                        {
                        colon = i;
                        }
                    else if ( currentCharacter == KSenSpace )
                        {
                        colon = KErrNotFound;
                        space = i;
                        }
                    }
                }

            // Now that we know place of '<' character and
            // also places of ':' and space characters (if
            // those two characters exist),
            // we can find out possible prefix and localname.
            if ( i > 0 )
                {
                TPtrC8 localNamePtr(KNullDesC8);
                TPtrC8 prefixPtr(KNullDesC8);
                if ( colon != KErrNotFound )
                    {
                    // Both Prefix and LocalName can be found.
                    if ( space != KErrNotFound )
                        {
                        localNamePtr.Set(ipContentBuf->Ptr(colon+1).MidTPtr(0, space-colon-1));
                        }
                    else
                        {
                        localNamePtr.Set(ipContentBuf->Ptr(colon+1).MidTPtr(0, size-colon-2));
                        }
                    prefixPtr.Set(ipContentBuf->Ptr(i+1).MidTPtr(0, colon-i-1));
                    }
                else
                    {
                    // Only LocalName can be found.
                    if ( space != KErrNotFound )
                        {
                        localNamePtr.Set(ipContentBuf->Ptr(i+1).MidTPtr(0, space-i-1));
                        }
                    else
                        {
                        localNamePtr.Set(ipContentBuf->Ptr(i+1).MidTPtr(0, size-i-2));
                        }
                    }
                
                // Do comparison for localname and prefix of
                // this EndTag
                if ( ( localNamePtr == saxLocalName ) && 
                     ( prefixPtr == saxPrefix ) )
                    {
                    // LocalName and prefix matched. So
                    // the EndTag should not be written.
                    // => Now the last character '>' of StartTag can
                    //    be replaced with characters '\' and '>'
                    //    which means that element is closed without
                    //    separate EndTag.
                    ipContentBuf->Delete((ipContentBuf->Size()-1),1);
                    ipContentBuf->InsertL((ipContentBuf->Size()), KSenSlash);
                    ipContentWriteStream->WriteL(KSenGreaterThan);
                    writeEndTag = EFalse;
                    }
                }
            }
        }
    
    if ( writeEndTag )
        {
        ipContentWriteStream->WriteL(KSenLessThanSlash());
        
        if ( saxPrefix.Length() > 0)
            {
            HBufC8*  pQName = HBufC8::NewLC( saxPrefix.Length()
                                             +KSenColon().Length()
                                             +saxLocalName.Length());
            TPtr8 qname = pQName->Des();
            qname.Append(saxPrefix);
            qname.Append(KSenColon);
            qname.Append(saxLocalName);
            ipContentWriteStream->WriteL(qname);
            CleanupStack::PopAndDestroy(pQName);
            }
        else
            {
            ipContentWriteStream->WriteL(saxLocalName);
            }
       
        ipContentWriteStream->WriteL(KSenGreaterThan());
        }    
    }

EXPORT_C TXmlEngNamespace CSenFragmentBase::Namespace(const TDesC8& aPrefix)
    {
    TXmlEngNamespace ns;
    if (aPrefix.Length() == 0) return ns;
    TRAP_IGNORE
        (    
        TXmlEngElement element = AsElementL();
        ns = element.LookupNamespaceByPrefixL(aPrefix);
        )
    return ns;
    }

/*EXPORT_C void CSenFragmentBase::DetachL()
    {
    //First add all the namespaces referred to in the content.
    if (iNamespaces.Count() > 0)
        {
        TInt count(iNamespaces.Count());
        for (TInt i=0; i<count; i++)
            {
            CSenNamespace* pNamespace = (CSenNamespace*) iNamespaces[i];
            ipElement->AddNamespaceL(*pNamespace, EFalse);
            //TRAPD(err, ipElement->AddNamespaceL(*pNamespace, EFalse));
            //if (err) ;
            }
        }
    //Detach the element from its parent.
    ipElement->DetachL();
    }*/

EXPORT_C TPtrC8 CSenFragmentBase::LocalName() const
    {
    __ASSERT_ALWAYS(iElement.NotNull(), User::Panic(KSenFragmentPanic, EFragmentElementNotInitialized));
        
    return iElement.Name();
    }

EXPORT_C TPtrC8 CSenFragmentBase::NsUri() const
    {
    __ASSERT_ALWAYS(iElement.NotNull(), User::Panic(KSenFragmentPanic, EFragmentElementNotInitialized));

    return iElement.NamespaceUri();
    }

EXPORT_C TPtrC8 CSenFragmentBase::NsPrefix() const
    {
    __ASSERT_ALWAYS(iElement.NotNull(), User::Panic(KSenFragmentPanic, EFragmentElementNotInitialized));

    return iElement.Prefix();
    }
    
EXPORT_C TBool CSenFragmentBase::ConsistsOfL(TXmlEngElement& aElement, TXmlEngElement& aCandidate)
    {
    // First check the names and namespaces
    TPtrC8 elementLocalName         = aElement.Name();
    TPtrC8 candidateLocalName       = aCandidate.Name();
    // Check localnames (element should always have localname
    //                  <=> localname can't be Null).
    if ( elementLocalName != candidateLocalName )
        {
        return EFalse;
        }
        
    TPtrC8 elementNamespaceUri      = aElement.NamespaceUri();
    TPtrC8 candidateNamespaceUri    = aCandidate.NamespaceUri();
    // Check namespaceUris (element does not always have namespaceUri
    //                      <=> namespaceUri can be Null).
    if ( elementNamespaceUri != KNullDesC8 && candidateNamespaceUri != KNullDesC8 )
        {
        if ( elementNamespaceUri != candidateNamespaceUri )
            {
            return EFalse;
            }
        }
    else
        {
        if ( elementNamespaceUri != KNullDesC8 || candidateNamespaceUri != KNullDesC8 )
            {
            return EFalse;
            }
        }
        
    TPtrC8 elementPrefix            = aElement.Prefix();
    TPtrC8 candidatePrefix          = aCandidate.Prefix();
    // Check prefixes (element does not always have prefix
    //                 <=> prefix can be Null).
    if ( elementPrefix != KNullDesC8 && candidatePrefix != KNullDesC8 )
        {
        if ( elementPrefix != candidatePrefix )
            {
            return EFalse;
            }
        }
    else
        {
        if ( elementPrefix != KNullDesC8 || candidatePrefix != KNullDesC8 )
            {
            return EFalse;
            }
        }

    RBuf8 candidateContent;
    aCandidate.WholeTextContentsCopyL(candidateContent);
    CleanupClosePushL(candidateContent);
    RBuf8 content;
    aElement.WholeTextContentsCopyL(content);
    CleanupClosePushL(content);
    if ( candidateContent != content )
        {
        CleanupStack::PopAndDestroy(&content);
        CleanupStack::PopAndDestroy(&candidateContent);
        return EFalse;  // Content doesn't match => no match
        }
    CleanupStack::PopAndDestroy(&content);
    CleanupStack::PopAndDestroy(&candidateContent);
    
    // Then handle the children
    RXmlEngNodeList<TXmlEngElement> candidateChildren;
    CleanupClosePushL(candidateChildren);
    aCandidate.GetChildElements(candidateChildren);

    RXmlEngNodeList<TXmlEngElement> children;
    CleanupClosePushL(children);
    aElement.GetChildElements(children);
    
    // Element should have at least as many child elements
    // as candidateElement has.
    TInt childrenCount = children.Count();
    TInt candidateChildrenCount = candidateChildren.Count();
    if ( childrenCount < candidateChildrenCount )
        {
        CleanupStack::PopAndDestroy(&children);
        CleanupStack::PopAndDestroy(&candidateChildren);
        return EFalse;
        }
    
    // Every child element of candidate should be found
    // from element.
    while ( candidateChildren.HasNext() )
        {
        TXmlEngElement candidateMatchChild = candidateChildren.Next();
        RXmlEngNodeList<TXmlEngElement> matchChilds;
        CleanupClosePushL(matchChilds);

        aElement.GetElementsByTagNameL(matchChilds,
                                       candidateMatchChild.Name(),
                                       candidateMatchChild.NamespaceUri());
        if ( !matchChilds.HasNext() )
            {
            CleanupStack::PopAndDestroy(&matchChilds);
            CleanupStack::PopAndDestroy(&children);
            CleanupStack::PopAndDestroy(&candidateChildren);
            return EFalse;
            }
        else
            {
            TBool found = EFalse;
            while ( matchChilds.HasNext() )
                {
                TXmlEngElement matchChild = matchChilds.Next();
                found = ConsistsOfL(matchChild, candidateMatchChild);
                if ( found ) break;
                }
            if ( !found )
                {
                CleanupStack::PopAndDestroy(&matchChilds);
                CleanupStack::PopAndDestroy(&children);
                CleanupStack::PopAndDestroy(&candidateChildren);
                return EFalse;
                }
            }
            
        CleanupStack::PopAndDestroy(&matchChilds);
        }
        
    CleanupStack::PopAndDestroy(&children);
    CleanupStack::PopAndDestroy(&candidateChildren);
    return ETrue;    
    }

EXPORT_C TBool CSenFragmentBase::ConsistsOfL(CSenFragmentBase& aCandidate)
    {
    TXmlEngElement element          = AsElementL();
    TXmlEngElement candidateElement = aCandidate.AsElementL();
    return ConsistsOfL(element, candidateElement);
    }

EXPORT_C void CSenFragmentBase::SetContentHandler(
                                            CSenFragmentBase& aContentHandler)
    {
    ipParser->SetContentHandler(aContentHandler);
    }

EXPORT_C void CSenFragmentBase::SetContentL(const TDesC8& aContent)
    {
    TXmlEngElement element = AsElementL();
    element.SetTextNoEncL(aContent);
    }

EXPORT_C void CSenFragmentBase::AddContentL(const TDesC8& aContent)
    {
    TPtrC8 content = ContentL();
    TXmlEngElement element = AsElementL();
    if ( content.Length() > 0 )
        {
        HBufC8* pContent = HBufC8::NewLC( content.Length() + aContent.Length() );
        TPtr8 ptrContent = pContent->Des();
        ptrContent.Append(content);
        ptrContent.Append(aContent);
        element.SetTextNoEncL(*pContent);
        CleanupStack::PopAndDestroy(pContent);
        }
    else
        {
        element.SetTextNoEncL(aContent);
        }
    }
    
EXPORT_C void CSenFragmentBase::SetDocument(RSenDocument& aDocument)
    {
    iDocument.Close();
    iDocument = aDocument.Copy();
    }

CSenNamespaceData::~CSenNamespaceData()
    {
    delete ipNamespaceUri;
    delete ipPrefix;
    delete ipLocalName;
    }

// End of File


