Qt-based BB10 API Examples Documentation

qtsoap.cpp Example File

soapxml/src/qtsoap/qtsoap.cpp
    /****************************************************************************
    **
    ** Copyright (C) 2010, 2013  Nokia Corporation and/or its subsidiary(-ies).
    ** All rights reserved.
    **
    ** Contact: Nokia Corporation (qt-info@nokia.com)
    **
    ** This file is part of a Qt Solutions component.
    **
    ** You may use this file under the terms of the BSD license as follows:
    **
    ** "Redistribution and use in source and binary forms, with or without
    ** modification, are permitted provided that the following conditions are
    ** met:
    **   * Redistributions of source code must retain the above copyright
    **     notice, this list of conditions and the following disclaimer.
    **   * Redistributions in binary form must reproduce the above copyright
    **     notice, this list of conditions and the following disclaimer in
    **     the documentation and/or other materials provided with the
    **     distribution.
    **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
    **     the names of its contributors may be used to endorse or promote
    **     products derived from this software without specific prior written
    **     permission.
    **
    ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
    **
    ****************************************************************************/

    #include "qtsoap.h"
    #include <QtCore/QSet>
    #include <QtNetwork/QNetworkRequest>
    #include <QtNetwork/QNetworkReply>

    /*! \page qtsoap-overview.html

        \title Qt SOAP component

        \tableofcontents

        \target overview
        \section1 Overview of the SOAP support in the QtSoap classes

        QtSoapMessage provides an interface for creating, inspecting and
        modifying SOAP messages. It has convenience functions for
        generating method requests and inspecting method response
        messages, and also functions that provide easy access to SOAP
        Fault messages.

        The QtSoapType class allows you to inspect SOAP messages with no
        knowledge of XML or DOM. Header and body items are all derived
        from QtSoapType, and through easy accessors and iterators, this
        class and its derivatives make it easy to build arrays
        (QtSoapArray), structs (QtSoapStruct) and simple types like
        String, Integer and Boolean (QtSoapSimpleType).

        Finally, QtSoapHttpTransport provides a convenient way to submit
        SOAP messages to a host via the HTTP protocol.

        \target classes
        \section1 The SOAP classes

        \table
        \header \i Class \i Short description
        \row    \i \l QtSoapMessage
            \i Represents a SOAP message
        \row    \i \l QtSoapQName
            \i Represents qualified names (QNames)
        \row    \i \l QtSoapType
            \i A superclass for all data constructs in a SOAP message.
        \row    \i \l QtSoapArray
            \i Represents a SOAP array
        \row    \i \l QtSoapArrayIterator
            \i Lets you iterate over all the values in a SOAP array
        \row    \i \l QtSoapStruct
            \i Represents a SOAP struct
        \row    \i \l QtSoapStructIterator
            \i Lets you iterate over all the values in a SOAP array
        \row    \i \l QtSoapSimpleType
            \i Represents simple SOAP types such as String, Integer and Boolean.
        \row    \i \l QtSoapHttpTransport
            \i Provides a method for transmitting SOAP messages to an
            HTTP server and for getting the SOAP reply.
        \endtable

        \target partial
        \section1 Status of the SOAP component

        This is a partial implementation of the SOAP v1.1 protocol.

        \list
        \i Server side SOAP is not supported.
        \i References to values (id and href attributes) are not supported.
        \i Only arrays with less than 5 dimensions are supported.
        \i Namespaces for types are not checked. Only the type names are used.
        \i The encodingStyle attribute is ignored. The serialization and
           encoding rules from section 5 in the SOAP v1.1 specification are
           assumed regardless of the value of the encodingStyle attribute.
        \i QtSoapType does not have accessors for attributes, which means
           for example that actor, mustUnderstand and so on are not
           accessible in headers.
        \i The SOAP root attribute is not supported.
        \endlist
    */

    namespace {
        QString localName(const QString &tagName)
        {
        int pos;
        if ((pos = tagName.indexOf(':')))
            return tagName.right(tagName.length() - pos - 1);

        return tagName;
        }

        QString prefix(const QString &tagName)
        {
        int pos;
        if ((pos = tagName.indexOf(':')))
            return tagName.left(pos);

        return tagName;
        }

    }

    /*! \class QtSoapQName qtsoap.h

        \brief The QtSoapQName class provides a wrapper for QNames (names with
        namespaces).

        This class is used extensively in QtSoap to define and identify
        header and body elements, including method and argument names.

        The QtSoapQName consists of a name and a URI. The URI is used as
        the name's namespace, i.e. the name is qualified (hence 'Q'-Name)
        by the URI. The name() and uri() functions return the QNames's
        name and URI.

        The QtSoapQName can be empty. It can also have just a name with no
        URI. Special handling is often applied to a QtSoapQName that has
        no URI. Typically, if a QName with no namespace is used in an
        element in a SOAP document that already has a default namespace
        defined, then that namespace will be applied to the QName.

        \code
        QtSoapMessage message;

        message.setMethod(QtSoapQName("sendMessage", "http://messenging.example.com/"));
        message.addMethodArgument(QtSoapSimpleType(QtSoapQName("a"), 15));
        \endcode
    */

    /*!
        Constructs a QName. Sets the QName name to \a name and the URI to
        \a uri.
    */
    QtSoapQName::QtSoapQName(const QString &name, const QString &uri)
        : n(name), nuri(uri)
    {
    }

    /*!
        Destructs the QtSoapQName.
    */
    QtSoapQName::~QtSoapQName()
    {
    }

    /*!
        Returns QName's name.
    */
    QString QtSoapQName::name() const
    {
        return n;
    }

    /*!
        Returns the QName's URI.
    */
    QString QtSoapQName::uri() const
    {
        return nuri;
    }

    /*!
        Sets the QName's name to \a s, and sets the URI to an empty string.
    */
    QtSoapQName &QtSoapQName::operator =(const QString &s)
    {
        n = s;
        nuri = "";

        return *this;
    }

    /*!
        \fn bool operator==(const QtSoapQName &s1, const QtSoapQName &s2)

        \relates QtSoapQName

        If \a s2 has a non-empty URI, this function returns true if the
        merge of the URI and the name of \a s1 is equal to that of \a s2;
        otherwise it returns false.

        If \a s2 has an empty URI, this function returns true if the name
        of \a s1 is equal to the name of \a s2; otherwise it returns false.

        The comparison is case-insensitive.
    */
    bool operator ==(const QtSoapQName &s1, const QtSoapQName &s2)
    {
        if (s2.uri() == "")
        return s1.name().toLower() == s2.name().toLower();

        return s1.name().toLower() == s2.name().toLower()
          && s1.uri().toLower() == s2.uri().toLower();
    }

    /*!
        \fn bool operator<(const QtSoapQName &s1, const QtSoapQName &s2)

        \relates QtSoapQName

        If \a s2 has a non-empty URI, this function returns true if the
        merge of the URI and the name of \a s1 is lexically less than that
        of \a s2; otherwise it returns false.

        If \a s2 has an empty URI, this function returns true if the name
        of \a s1 is lexically less than the name of \a s2; otherwise
        it returns false.

        The comparison is case-insensitive.
    */
    bool operator <(const QtSoapQName &s1, const QtSoapQName &s2)
    {
        if (s2.uri() == "")
        return s1.name().toLower() < s2.name().toLower();

        return (s1.uri().toLower()+s1.name().toLower()) < (s2.uri().toLower()+s2.name().toLower());
    }

    /*! \class QtSoapType qtsoap.h
        \brief The QtSoapType class is the base class for all SOAP types
        in QtSoap.

        Although it is not used to create data types, a QtSoapType
        reference can be conveniently used to inspect a tree of QtSoapType
        subclasses. Accessors from this base class, such as operator[](),
        allow safe navigation.

        \code
        const QtSoapType &root = message.returnValue();
        if (root["fault"].isValid()) {
        qWarning("Warning: %s", root["fault"]["faultstring"].toString().toLatin1().constData());
        }
        \endcode

        This class holds the name(), type(), id() and href() of all its
        derived types.

        If a QtSoapType reference or pointer points to a QtSoapStruct, a
        QtSoapArray or a QtSoapSimpleType, isValid() returns true.

        \sa QtSoapStruct, QtSoapArray, QtSoapSimpleType
    */

    /*!
        \class QtSoapStruct qtsoap.h
        \brief The QtSoapStruct class is an implementation of the SOAP
        struct type.

        A SOAP struct is a dictionary of QtSoapTypes where entries are
        looked up by name. Entries in a struct can be of any QtSoapType
        type, such as QtSoapArray, QtSoapStruct or QtSoapSimpleType.

        The struct can be created in several ways. parse() generates a
        struct by analyzing a QDomNode. insert() is used to add items
        manually.

        \code
        QtSoapStruct myStruct(QtSoapQName("myStruct"));

        myStruct.insert(new QtSoapSimpleType(QtSoapQName("item1"), 5));
        myStruct.insert(new QtSoapSimpleType(QtSoapQName("item2"), "hello"));
        myStruct.insert(new QtSoapSimpleType(QtSoapQName("item3"), true));
        \endcode

        Use the operator[]() or at() when looking up entries in a struct
        by name. If the names are unknown, QtSoapStructIterator lets you
        iterate through all the items.

        \code
        QtSoapType &helloItem = myStruct["Hello"];
        \endcode

        toDomElement() converts the QtSoapStruct to a DomElement.

        \sa QtSoapStructIterator, QtSoapType, QtSoapArray, QtSoapSimpleType
    */

    /*! \class QtSoapStructIterator
        \brief The QtSoapStructIterator class provides an iterator for
        traversing the items in a QtSoapStruct.

        The iterator is created by passing a QtSoapStruct to the
        constructor. It it not defined which item the iterator initially
        will point to. Neither is the order in which the items are
        processed.

        key() returns the name of the current item. data() and current()
        return a pointer to the current item, or 0 if there is none.
        operator++() navigates to the next item in the struct.

        \code
        for (QtSoapStructIterator it(myStruct); it.current(); ++it) {
        QtSoapType *item = it.data();
        // process item
        }
        \endcode

        \sa QtSoapArrayIterator
    */

    /*! \class QtSoapArray qtsoap.h
        \brief The QtSoapArray class is an implementation of the SOAP
        array type.

        A SOAP array is a sequence of QtSoapType objects such as
        QtSoapArrays, QtSoapStructs or QtSoapSimpleTypes, and they are
        accessible through their ordinal position. An array can be
        consecutive (0, 1, 2, 3, ...) or sparse (1, 5, 6, 10, ...) and
        they can be multidimensional ((0, 0), (0, 1), ...). QtSoapArray
        supports arrays of up to 5 dimensions. The size and dimensions of
        the array are set in the constructor. The default constructor
        produces a one dimensional array, with an unset size, meaning that
        the array can grow as required.

        All elements in a SOAP array must be of the same type. Inserting
        different types will result in a run time error.

        The parse() function builds the array by analyzing a QDomNode from
        a SOAP document. count() returns the number of items in the array.

        Retrieve items in the array with at() or operator[](). Note that
        operator[]() only works with one dimensional arrays, but there are
        at() functions for arrays of up to 5 dimensions.
        QtSoapArrayIterator lets you iterate through all items in an
        array.

        Use insert() or append() to insert items into an array manually.
        append() only works with one dimensional arrays.

        toDomElement() returns a QDomElement representation of the SOAP
        array.

        \code
        QtSoapArray array;

        array.insert(0, new QtSoapSimpleType(QtSoapQName("Peter"), "peter"));
        array.insert(1, new QtSoapSimpleType(QtSoapQName("Lisa"), "lisa"));
        array.insert(2, new QtSoapSimpleType(QtSoapQName("Paul"), "paul"));
        array.insert(3, new QtSoapSimpleType(QtSoapQName("Heather"), "heather"));
        \endcode

        \sa QtSoapType, QtSoapStruct, QtSoapSimpleType
    */

    /*! \class QtSoapArrayIterator qtsoap.h
        \brief The QtSoapArrayIterator class provides an iterator for
        traversing the items in a QtSoapArray.

        The items are traversed in ascending order of index position,
        depth first.

        \code
        // Construct a 2x2 array of Strings.
        QtSoapArray array("Array of strings", String, 2, 2);
        array.insert(0, 0, new QtSoapSimpleType(Q4SoapQName("top left"), "top left");
        array.insert(0, 1, new QtSoapSimpleType(Q4SoapQName("top right"), "top right");
        array.insert(1, 0, new QtSoapSimpleType(Q4SoapQName("bottom left"), "bottom left");
        array.insert(1, 1, new QtSoapSimpleType(Q4SoapQName("bottom right"), "bottom right");

        // Traverse all items.
        QtSoapArrayIterator it(array);
        while (!it.current()) {

          // Find the position of the current element.
          int pos1, pos2;
          it.pos(&pos1, &pos2);

          qDebug() << "Position (" << pos1 << ", " << pos2 << ") is "
                   << "the " << it.current()->toString() << " coordinate of the grid." << endl;

          ++it;
        }
        \endcode
    */

    /*! \class QtSoapSimpleType qtsoap.h
        \brief The QtSoapSimpleType class provides a container for all
        simple SOAP types, such as strings, integers and booleans.

        \sa QtSoapType, QtSoapStruct, QtSoapArray
    */

    /*! \enum QtSoapType::Type

        SOAP supports the types described in XML Schema Part 2: Datatypes
        listed at \l http://www.w3.org/TR/xmlschema-2/. The following
        values are represented using QtSoapSimpleType, except where noted.

        \value AnyURI
        \value Array Represented by QtSoapArray
        \value Base64Binary
        \value Boolean
        \value Byte
        \value Date
        \value DateTime
        \value Decimal
        \value Double
        \value Duration
        \value ENTITY
        \value Float
        \value GDay
        \value GMonth
        \value GMonthDay
        \value GYear
        \value GYearMonth
        \value HexBinary
        \value ID
        \value IDREF
        \value Int
        \value Integer
        \value Language
        \value Long
        \value NCName
        \value NMTOKEN
        \value NOTATION
        \value Name
        \value NegativeInteger
        \value NonNegativeInteger
        \value NonPositiveInteger
        \value NormalizedString
        \value Other
        \value PositiveInteger
        \value QName
        \value Short
        \value String
        \value Struct Represented by QtSoapStruct
        \value Time
        \value Token
        \value UnsignedByte
        \value UnsignedInt
        \value UnsignedLong
        \value UnsignedShort
    */

    /*!
        Constructs a QtSoapType.
    */
    QtSoapType::QtSoapType()
    {
        t = Other;
        errorStr = "Unknown error";
    }

    /*!
        Constructs a QtSoapType whose name is \a name and type is \a type.
        This contructor is usually only called by constructors in
        subclasses.
    */
    QtSoapType::QtSoapType(const QtSoapQName &name, Type type)
        : t(type), n(name)
    {
        errorStr = "Unknown error";
    }

    /*!
        Creates a QtSoapType copy of \a copy.
    */
    QtSoapType::QtSoapType(const QtSoapType &copy)
        : t(copy.t), errorStr(copy.errorStr), i(copy.i),
          n(copy.n), u(copy.u), h(copy.h)
    {
    }

    /*!
        Destructs a QtSoapType.
    */
    QtSoapType::~QtSoapType()
    {
    }

    /*!
        Clears any contents. In this base implementation, clear() does
        nothing.
    */
    void QtSoapType::clear()
    {
    }

    /*!
        Makes this QtSoapType equal to \a copy.
    */
    QtSoapType &QtSoapType::operator =(const QtSoapType &copy)
    {
        t = copy.t;
        errorStr = copy.errorStr;
        i = copy.i;
        n = copy.n;
        u = copy.u;
        h = copy.h;
        return *this;
    }

    /*!
        Returns true if this object is of type QtSoapStruct, QtSoapArray
        or QtSoapSimpletype; otherwise returns false.
    */
    bool QtSoapType::isValid() const
    {
        return false;
    }

    /*!
        Returns the QString equivalent of type \a t.
    */
    QString QtSoapType::typeToName(QtSoapType::Type t)
    {
        switch (t) {
        case Duration: return "duration";
        case DateTime: return "dateTime";
        case Time: return "time";
        case Date: return "date";
        case GYearMonth: return "gYearMonth";
        case GYear: return "gYear";
        case GMonthDay: return "gMonthDay";
        case GDay: return "gDay";
        case GMonth: return "gMonth";
        case Boolean: return "boolean";
        case Base64Binary: return "base64Binary";
        case HexBinary: return "hexBinary";
        case Float: return "float";
        case Double: return "double";
        case AnyURI: return "anyURI";
        case QName: return "QName";
        case NOTATION: return "NOTATION";
        case String: return "string";
        case NormalizedString: return "normalizedString";
        case Token: return "token";
        case Language: return "language";
        case Name: return "name";
        case NMTOKEN: return "NMToken";
        case NCName: return "NCName";
        case ID: return "ID";
        case IDREF: return "IDREF";
        case ENTITY: return "ENTITY";
        case Decimal: return "decimal";
        case Integer: return "integer";
        case NonPositiveInteger: return "nonPositiveInteger";
        case NegativeInteger: return "negativeInteger";
        case Long: return "long";
        case Int: return "int";
        case Short: return "short";
        case Byte: return "byte";
        case NonNegativeInteger: return "nonNegativeInteger";
        case UnsignedLong: return "unsignedLong";
        case PositiveInteger: return "positiveInteger";
        case UnsignedInt: return "unsignedInt";
        case UnsignedShort: return "unsignedShort";
        case UnsignedByte: return "unsignedByte";
        case Array: return "array";
        case Struct: return "struct";
        default: return "other";
        }
    }

    /*!
        Returns the QtSoapType::Type called \a name.
    */
    QtSoapType::Type QtSoapType::nameToType(const QString &name)
    {
        const QString type = name.trimmed().toLower();

        if (type == "string")
        return String;
        else if (type == "normalizedstring")
        return NormalizedString;
        else if (type == "token")
        return Token;
        else if (type == "language")
        return Language;
        else if (type == "name")
        return Name;
        else if (type == "ncname")
        return NCName;
        else if (type == "nmtoken")
        return NMTOKEN;
        else if (type == "id")
        return ID;
        else if (type == "idref")
        return IDREF;
        else if (type == "entity")
        return ENTITY;
        else if (type == "base64binary")
        return Base64Binary;
        else if (type == "hexBinary")
        return HexBinary;
        else if (type == "anyuri")
        return AnyURI;
        else if (type == "qname")
        return QName;
        else if (type == "notation")
        return NOTATION;
        else if (type == "duration")
        return Duration;
        else if (type == "datetime")
        return DateTime;
        else if (type == "time")
        return Time;
        else if (type == "date")
        return Date;
        else if (type == "gyearmonth")
        return GYearMonth;
        else if (type == "gyear")
        return GYear;
        else if (type == "gmonthday")
        return GMonthDay;
        else if (type == "gday")
        return GDay;
        else if (type == "gmonth")
        return GMonth;
        else if (type == "decimal")
        return Decimal;
        else if (type == "integer")
        return Integer;
        else if (type == "nonPositiveinteger")
        return NonPositiveInteger;
        else if (type == "negativeinteger")
        return NegativeInteger;
        else if (type == "long")
        return Long;
        else if (type == "int")
        return Int;
        else if (type == "short")
        return Short;
        else if (type == "byte")
        return Byte;
        else if (type == "nonnegativeinteger")
        return NonNegativeInteger;
        else if (type == "unsignedlong")
        return UnsignedLong;
        else if (type == "unsignedint")
        return UnsignedInt;
        else if (type == "unsignedshort")
        return UnsignedShort;
        else if (type == "unsignedbyte")
        return UnsignedByte;
        else if (type == "positiveinteger")
        return PositiveInteger;
        else if (type == "float")
        return Float;
        else if (type == "double")
        return Double;
        else if (type == "boolean")
        return Boolean;
        else
        return Other;
    }

    /*!
        Returns QString::null.
    */
    QString QtSoapType::toString() const
    {
        return QString::null;
    }

    /*!
        Returns 0.
    */
    int QtSoapType::toInt() const
    {
        return 0;
    }

    /*!
        Returns false.
    */
    bool QtSoapType::toBool() const
    {
        return false;
    }

    /*!
        Returns the QDomElement representation of this QtSoapType
        as a child of \a document.
    */
    QDomElement QtSoapType::toDomElement(QDomDocument document) const
    {
        Q_UNUSED(document);
        return QDomElement();
    }

    /*!
        Returns the QString representation of this QtSoapType's type.
    */
    QString QtSoapType::typeName() const
    {
        return QtSoapType::typeToName(type());
    }

    /*!
        Returns the type as a QtSoapType::Type.
    */
    QtSoapType::Type QtSoapType::type() const
    {
        return t;
    }

    /*!
        Returns the QName (qualified name) of this QtSoapType.
    */
    QtSoapQName QtSoapType::name() const
    {
        return n;
    }

    /*!
        Returns the ID of this QtSoapType.
    */
    QString QtSoapType::id() const
    {
        return i;
    }

    /*!
        Returns the href attribute of this QtSoapType.
    */
    QString QtSoapType::href() const
    {
        return h;
    }

    /*!
        Sets the QName (qualified name) of this QtSoapType to \a name.
    */
    void QtSoapType::setName(const QtSoapQName &name)
    {
        this->n = name;
    }

    /*!
        Sets the ID of this QtSoapType to \a i.
    */
    void QtSoapType::setId(const QString &i)
    {
        this->i = i;
    }

    /*!
        Sets the href attribute of this QtSoapType to \a h.
    */
    void QtSoapType::setHref(const QString &h)
    {
        this->h = h;
    }

    /*!
        Returns the value of this QtSoapType. In the base implementation,
        an invalid QVariant() is returned.
    */
    QVariant QtSoapType::value() const
    {
        return QVariant();
    }

    /*!
        Returns a human readable explanation of the most recent error.
    */
    QString QtSoapType::errorString() const
    {
        return errorStr;
    }

    /*!
        Returns the number of child items in this QtSoapType. In the base
        implementation, this returns 0.
    */
    int QtSoapType::count() const
    {
        return 0;
    }

    /*!
        Returns a reference to the child item at ordinal position \a pos.
        If no item exists at this position, returns an empty QtSoapType.
    */
    QtSoapType &QtSoapType::operator [](int /* pos */ )
    {
        static QtSoapType NIL;
        return NIL;
    }

    /*!
        \overload

        Returns a reference to the child item whose QName (qualified name)
        is \a key. If no item exists with this key an empty QtSoapType is
        returned.
    */
    QtSoapType &QtSoapType::operator [](const QtSoapQName & /* key */)
    {
        static QtSoapType NIL;
        return NIL;
    }

    /*!
        \overload

        Returns a reference to the child item whose QName (qualified name)
        is \a key, regardless of the qualified name's URI. If no item
        exists with this key, an empty QtSoapType is returned.
    */
    QtSoapType &QtSoapType::operator [](const QString & /* key */)
    {
        static QtSoapType NIL;
        return NIL;
    }

    /*!
        \overload

        Returns a reference to the child item at ordinal position \a pos.
        If no item exists at this position, returns an empty QtSoapType.
    */
    const QtSoapType &QtSoapType::operator [](int /* pos */) const
    {
        static QtSoapType NIL;
        return NIL;
    }

    /*!
        \overload

        Returns a reference to the child item whose QName (qualified name)
        is \a key. If no item exists with this key, returns an empty
        QtSoapType.
    */
    const QtSoapType &QtSoapType::operator [](const QtSoapQName & /* key */) const
    {
        static QtSoapType NIL;
        return NIL;
    }

    /*!
        \overload

        Returns a reference to the child item whose QName (qualified name)
        is \a key, regardless of the qualified name's URI. If no item
        exists with this key, returns an empty QtSoapType.
    */
    const QtSoapType &QtSoapType::operator [](const QString & /* key */) const
    {
        static QtSoapType NIL;
        return NIL;
    }

    /*!
        Attempts to interpret \a node as a QtSoapType, and returns true if
        successful. This base implementation always returns false.
    */
    bool QtSoapType::parse(QDomNode /* node */)
    {
        return false;
    }

    /*!
        \overload

        Constructs an empty one dimensional QtSoapArray whose element type
        is undefined. The first insert will decide what type of elements
        the array can contain.
    */
    QtSoapArray::QtSoapArray()
        : QtSoapType(QtSoapQName(), Array), arrayType(Other), order(1)
    {
        lastIndex = 0;
        siz0 = 0;
        siz1 = 0;
        siz2 = 0;
        siz3 = 0;
        siz4 = 0;
    }

    /*!
        Constructs an empty QtSoapArray whose QName (qualified name) is \a
        name, that contains elements of type \a type, and whose dimensions
        are given by \a size0, \a size1, \a size2, \a size3 and \a size4.

        To construct a one dimensional array of size 5, set \a size0 = 5. To
        create a two dimensional array of size 5x10, set \a size0 = 5 and \a
        size1 = 10. The maximum dimension of a QtSoapArray is 5.
    */
    QtSoapArray::QtSoapArray(const QtSoapQName &name, QtSoapType::Type type, int size0,
                 int size1, int size2, int size3, int size4)
        : QtSoapType(name, Array), lastIndex(0), arrayType(type),
          siz0(size0), siz1(size1), siz2(size2), siz3(size3),
          siz4(size4)
    {
        if (size4 != -1) order = 5;
        else if (size3 != -1) order = 4;
        else if (size2 != -1) order = 3;
        else if (size1 != -1) order = 2;
        else order = 1;
    }

    /*!
        Create a QtSoapArray that is a copy of \a copy.
    */
    QtSoapArray::QtSoapArray(const QtSoapArray &copy)
        : QtSoapType(copy)
    {
        *this = copy;
    }

    /*!
        Destructs the QtSoapArray.
    */
    QtSoapArray::~QtSoapArray()
    {
    }

    /*!
        Clears the contents, and the dimensions of the QtSoapArray.
    */
    void QtSoapArray::clear()
    {
        array.clear();
        lastIndex = 0;
        arrayType = Other;
        siz0 = siz1 = siz2 = siz3 = siz4 = 0;
        order = -1;
    }

    /*!
        Makes this QtSoapArray a copy of \a copy.
    */
    QtSoapArray &QtSoapArray::operator = (const QtSoapArray &copy)
    {
        if (this == &copy)
            return *this;
        t = copy.t;
        errorStr = copy.errorStr;
        i = copy.i;
        n = copy.n;
        u = copy.u;
        h = copy.h;
        lastIndex = copy.lastIndex;
        order = copy.order;
        siz0 = copy.siz0;
        siz1 = copy.siz1;
        siz2 = copy.siz2;
        siz3 = copy.siz3;
        siz4 = copy.siz4;
        array = copy.array;

        return *this;
    }

    /*!
        Appends the QtSoapType \a item to the end of this array, which must
        be one dimensional.

        \sa insert()
    */
    void QtSoapArray::append(QtSoapType *item)
    {
        if (order != 1) {
        qWarning("Attempted to insert item at position (%i) in %i-dimensional QtSoapArray.",
             lastIndex, order);
        return;
        }

        if (array.count() == 0) {
        array.insert(0, item);
        } else {
        array.insert(lastIndex + 1, item);
        ++lastIndex;
        }
    }

    /*!
        Inserts the QtSoapType \a item at the absolute position \a pos in
        the array. Note that this function can be used to insert items
        into arrays with any number of dimensions.

        If the array is one dimensional, then \a pos is simply the index
        position in the array. But if the array is multi-dimensional then
        \a pos is the absolute position. For example, if we have a two
        dimensional array [['a', 'b'], ['c', 'd'], ['e', 'f']], the
        element at position 0 is 'a', at position 1 is 'b', at position 2
        is 'c', and so on. (There are other insert() overloads that allow
        for each dimension to be specified individually.)
    */
    void QtSoapArray::insert(int pos, QtSoapType *item)
    {
        if (arrayType == Other)
        arrayType = item->type();

        if (item->type() != arrayType) {
        qWarning("Attempted to insert item of type \"%s\" in QtSoapArray of type \"%s\".",
             item->typeName().toLatin1().constData(), QtSoapType::typeToName(arrayType).toLatin1().constData());
        return;
        }

        if (order == -1)
        order = 1;
        else if (order == 1 && pos > lastIndex)
        lastIndex = pos;

        array.insert(pos, item);
    }

    /*!
        \overload

        Insert the QtoSoapType \a item at position \a pos0 x \a pos1 in a
        two dimensional array.
    */
    void QtSoapArray::insert(int pos0, int pos1, QtSoapType *item)
    {
        if (order != 2) {
        qWarning("Attempted to insert item at position (%i, %i)"
             " in %i-dimensional QtSoapArray.",
             pos0, pos1, order);
        return;
        }

        if (pos0 < 0 || pos0 >= siz0 || pos1 < 0 || pos1 >= siz1) {
        qWarning("Attempted to insert item at position (%i, %i)"
             " when range of QtSoapArray is (0..%i, 0..%i)",
             pos0, pos1, siz0 - 1, siz1 - 1);
        return;
        }

        insert((pos0 * siz1) + pos1, item);
    }

    /*!
        \overload

        Insert the QtoSoapType \a item at position \a pos0 x \a pos1 x \a
        pos2 in a three dimensional array.
    */
    void QtSoapArray::insert(int pos0, int pos1, int pos2, QtSoapType *item)
    {
        if (order != 3) {
        qWarning("Attempted to insert item at position (%i, %i, %i)"
             " in %i-dimensional QtSoapArray.",
             pos0, pos1, pos2, order);
        return;
        }

        if (pos0 < 0 || pos0 >= siz0 || pos1 < 0 || pos1 >= siz1 || pos2 < 0 || pos2 >= siz2) {
        qWarning("Attempted to insert item at position (%i, %i, %i)"
             " when range of QtSoapArray is (0..%i, 0..%i, 0..%i)",
             pos0, pos1, pos2, siz0 - 1, siz1 - 1, siz2 - 1);
        return;
        }

        insert((pos0 * siz2 * siz1) + (pos1 * siz2) + pos2, item);
    }

    /*!
        \overload

        Insert the QtoSoapType \a item at position \a pos0 x \a pos1 x \a
        pos2 x \a pos3 in a four dimensional array.
    */
    void QtSoapArray::insert(int pos0, int pos1, int pos2, int pos3, QtSoapType *item)
    {
        if (order != 4) {
        qWarning("Attempted to insert item at position (%i, %i, %i, %i)"
             " in %i-dimensional QtSoapArray.",
             pos0, pos1, pos2, pos3, order);
        return;
        }

        insert((pos0 * siz3 * siz2 * siz1)
           + (pos1 * siz3 * siz2)
           + (pos2 * siz3)
           + pos3,
           item);
    }

    /*!
        \overload

        Insert the QtoSoapType \a item at position \a pos0 x \a pos1 x \a
        pos2 x \a pos3 x \a pos4 in a five dimensional array.
    */
    void QtSoapArray::insert(int pos0, int pos1, int pos2, int pos3, int pos4,
                 QtSoapType *item)
    {
        if (order != 5) {
        qWarning("Attempted to insert item at position (%i, %i, %i, %i, %i)"
             " in %i-dimensional QtSoapArray.",
             pos0, pos1, pos2, pos3, pos4, order);
        return;
        }

        insert((pos0 * siz4 * siz3 * siz2 * siz1)
           + (pos1 * siz4 * siz3 * siz2)
           + (pos2 * siz4 * siz3)
           + (pos3 * siz4)
           + pos4,
           item);
    }

    /*! \internal

        Given the size and dimensions of the array, generates a string
        used to represent the array in XML. For example, a 1-dimensional
        array of size 5 would get [5], a 2-dimensional array of size 5x10
        would get [5,10].
    */
    QString QtSoapArray::arraySizeString() const
    {
        QString arraySize = "[";
        if (siz0 != -1) {
        arraySize += QString::number(siz0);
        if (order > 1) arraySize += "," + QString::number(siz1);
        if (order > 2) arraySize += "," + QString::number(siz2);
        if (order > 3) arraySize += "," + QString::number(siz3);
        if (order > 4) arraySize += "," + QString::number(siz4);
        }

        arraySize += "]";
        return arraySize;
    }

    /*! \internal

        Recursively inspects the items and any child arrays' items to
        generate the aggregate type of items in this array. It the array
        contains ints, returns "int[5]", but if the array is of arrays of
        arrays of ints, the function returns "int[][][5]".
    */
    QString QtSoapArray::arrayTypeString() const
    {
        if (arrayType != Array)
        return QtSoapType::typeToName(arrayType);

        QString atString;
        QtSoapArray *ar = const_cast<QtSoapArray *>(this);
        do {
        if (ar->count()    == 0)
            break;

        atString += ar->arraySizeString();

        QtSoapArrayIterator it(*const_cast<QtSoapArray *>(this));
        if (it.data()->type() != Array)
            break;

        ar = (QtSoapArray *)it.data();
        } while (ar);

        QtSoapArrayIterator it(*const_cast<QtSoapArray *>(this));
        if (ar->count() == 0)
        atString = QtSoapSimpleType::typeToName(Int) + atString;
        else
        atString = it.data()->typeName() + atString;

        return atString;
    }

    /*!
        Returns the QDomElement representation of this QtSoapArray. The
        returned QDomElement is created using \a doc.
    */
    QDomElement QtSoapArray::toDomElement(QDomDocument doc) const
    {
        QString prefix = QtSoapNamespaces::instance().prefixFor(n.uri());
        QDomElement a = n.uri() == ""
                ? doc.createElement( n.name())
                : doc.createElementNS(n.uri(), prefix + ":" + n.name());

        QString schemaprefix = QtSoapNamespaces::instance().prefixFor(XML_SCHEMA_INSTANCE);
        a.setAttributeNS(XML_SCHEMA_INSTANCE, schemaprefix + ":type", "xsd:Array");

        QString encprefix = QtSoapNamespaces::instance().prefixFor(SOAPv11_ENCODING);
        a.setAttributeNS(SOAPv11_ENCODING, encprefix + ":arrayType", "xsd:" + arrayTypeString());

        for (QtSoapArrayIterator i(*const_cast<QtSoapArray *>(this)); !i.atEnd(); ++i) {
        QDomElement item = i.data()->toDomElement(doc);
        item.setTagName("item");

        int pos0, pos1, pos2, pos3, pos4;
        i.pos(&pos0, &pos1, &pos2, &pos3, &pos4);

        QString position = "[" + QString::number(pos0);
        if (order > 1) position += "," + QString::number(pos1);
        if (order > 2) position += "," + QString::number(pos2);
        if (order > 3) position += "," + QString::number(pos3);
        if (order > 4) position += "," + QString::number(pos4);
        position += "]";

        QString envprefix = QtSoapNamespaces::instance().prefixFor(SOAPv11_ENVELOPE);
        item.setAttributeNS(SOAPv11_ENVELOPE, envprefix + ":position", position);
        a.appendChild(item);
        }

        return a;
    }

    /*! \reimp

        For this class, always returns true.
    */
    bool QtSoapArray::isValid() const
    {
        return true;
    }

    /*!
        Inspects \a node and builds the content of the QtSoapArray if \a
        node qualifies as a SOAP array. Returns true if it does; otherwise
        returns false.
    */
    bool QtSoapArray::parse(QDomNode node)
    {
        if (node.isNull() || !node.isElement())
        return false;

        QDomElement e = node.toElement();
        QDomAttr typeattr = e.attributeNode("type");
        if (!typeattr.isNull() && (localName(typeattr.value()).toLower() != "array"))
        return false;

        QDomNodeList children = e.childNodes();
        int c = children.count();
        array.clear();
        // ### array.resize(c);

        int pos = 0;
        for (int i = 0; i < c; ++i) {
        QDomNode n = children.item(i);
            if (n.isComment())
                continue;
        if (!n.isElement()){
            // ### An error in the soap document.
            return false;
        }

        QDomElement elem = n.toElement();

        QtSmartPtr<QtSoapType> type = QtSoapTypeFactory::instance().soapType(elem);
        if (!type.ptr()) {
            // ### An error in the soap document.
            return false;
        }

        // ### Check namespace
        QDomAttr posattr = elem.attributeNode("position");
        if (!posattr.isNull())
            pos = posattr.value().toInt();

        array.insert(pos, type);
        ++pos;
        }

        setName(QtSoapQName(localName(e.tagName()), e.namespaceURI()));
        return true;
    }

    /*!
        Returns the number of items in the array. Note that this is not
        the same as the size of the array, because the array may be sparse.
    */
    int QtSoapArray::count() const
    {
        return array.count();
    }

    /*!
        Returns a reference to the item at ordinal position \a pos. If
        there is no item at position \a pos, returns an empty QtSoapType.
    */
    QtSoapType &QtSoapArray::operator [](int pos)
    {
        return at(pos);
    }

    /*!
        \overload

        Returns a reference to the child item whose local name is \a s. If
        there is no item with this local name, returns an empty
        QtSoapType.
    */
    QtSoapType &QtSoapArray::operator [](const QString &s)
    {
        return QtSoapType::operator[](s);
    }

    /*!
        \overload

        Returns a reference to the child item whose QName (qualified name)
        is \a s. If there is no item with this name, returns an empty
        QtSoapType.
    */
    QtSoapType &QtSoapArray::operator [](const QtSoapQName &s)
    {
        return QtSoapType::operator[](s);
    }

    /*!
        \overload

        Returns a reference to the item at ordinal position \a pos. If
        there is no item at position \a pos, returns an empty QtSoapType.
    */
    const QtSoapType &QtSoapArray::operator [] (int pos) const
    {
        return at(pos);
    }

    /*!
        \overload

        Returns a reference to the child item whose local name is \a s. If
        there is no item with this local name, returns an empty
        QtSoapType.
    */
    const QtSoapType &QtSoapArray::operator [](const QString &s) const
    {
        return QtSoapType::operator[](s);
    }

    /*!
        \overload

        Returns a reference to the child item whose QName (qualified name)
        is \a s. If there is no item with this name, returns an empty
        QtSoapType.
    */
    const QtSoapType &QtSoapArray::operator [](const QtSoapQName &s) const
    {
        return QtSoapType::operator[](s);
    }

    /*!
        Returns a reference to the item at ordinal position \a pos. If
        there is no item at position \a pos, returns an empty QtSoapType.
    */
    QtSoapType &QtSoapArray::at(int pos)
    {
        static QtSoapType NIL;

        if (array.find(pos) != array.end())
        return *array[pos];
        else
        return NIL;
    }

    /*!
        \overload

        Returns a reference to the item at ordinal position \a pos0 x \a
        pos1 in a two dimensional array. If there is no such item, returns
        an empty QtSoapType.
    */
    QtSoapType &QtSoapArray::at(int pos0, int pos1)
    {
        return at(pos0 * siz1 + pos1);
    }

    /*!
        \overload

        Returns a reference to the item at ordinal position \a pos0 x \a
        pos1 x \a pos2 in a three dimensional array. If there is no such
        item, returns an empty QtSoapType.
    */
    QtSoapType &QtSoapArray::at(int pos0, int pos1, int pos2)
    {
        return at((pos0 * siz2 * siz1) + (pos1 * siz2) + pos2);
    }

    /*!
        \overload

        Returns a reference to the item at ordinal position \a pos0 x \a
        pos1 x \a pos2 x \a pos3 in a four dimensional array. If there is no
        such item, returns an empty QtSoapType.
    */
    QtSoapType &QtSoapArray::at(int pos0, int pos1, int pos2, int pos3)
    {
        return at((pos0 * siz3 * siz2 * siz1)
              + (pos1 * siz3 * siz2)
              + (pos2 * siz3)
              + pos3);
    }

    /*!
        \overload

        Returns a reference to the item at ordinal position \a pos0 x \a
        pos1 x \a pos2 x \a pos3 x \a pos4 in a five dimensional array. If
        there is no such item, returns an empty QtSoapType.
    */
    QtSoapType &QtSoapArray::at(int pos0, int pos1, int pos2, int pos3, int pos4)
    {
        return at((pos0 * siz4 * siz3 * siz2 * siz1)
              + (pos1 * siz4 * siz3 * siz2)
              + (pos2 * siz4 * siz3)
              + (pos3 * siz4)
              + pos4);
    }

    /*!
        \overload

        Returns a reference to the item at ordinal position \a pos. If
        there is no item at position \a pos, returns an empty QtSoapType.
    */
    const QtSoapType &QtSoapArray::at(int pos) const
    {
        static QtSoapType NIL;

        if (array.find(pos) != array.end())
        return *array[pos];
        else
        return NIL;
    }

    /*!
        \overload

        Returns a reference to the item at ordinal position \a pos0 x \a
        pos1 in a two dimensional array. If there is no such item, returns
        an empty QtSoapType.
    */
    const QtSoapType &QtSoapArray::at(int pos0, int pos1) const
    {
        return at(pos0 * siz1 + pos1);
    }

    /*!
        \overload

        Returns a reference to the item at ordinal position \a pos0 x \a
        pos1 x \a pos2 in a three dimensional array. If there is no such
        item, returns an empty QtSoapType.
    */
    const QtSoapType &QtSoapArray::at(int pos0, int pos1, int pos2) const
    {
        return at((pos0 * siz2 * siz1) + (pos1 * siz2) + pos2);
    }

    /*!
        \overload

        Returns a reference to the item at ordinal position \a pos0 x \a
        pos1 x \a pos2 x \a pos3 in a four dimensional array. If there is no
        such item, returns an empty QtSoapType.
    */
    const QtSoapType &QtSoapArray::at(int pos0, int pos1, int pos2, int pos3) const
    {
        return at((pos0 * siz3 * siz2 * siz1)
              + (pos1 * siz3 * siz2)
              + (pos2 * siz3)
              + pos3);
    }

    /*!
        \overload

        Returns a reference to the item at ordinal position \a pos0 x \a
        pos1 x \a pos2 x \a pos3 x \a pos4 in a five dimensional array. If
        there is no such item, returns an empty QtSoapType.
    */
    const QtSoapType &QtSoapArray::at(int pos0, int pos1, int pos2, int pos3, int pos4) const
    {
        return at((pos0 * siz4 * siz3 * siz2 * siz1)
              + (pos1 * siz4 * siz3 * siz2)
              + (pos2 * siz4 * siz3)
              + (pos3 * siz4)
              + pos4);
    }

    /*!
        Constructs a QtSoapArrayIterator on \a array, initializing
        the iterator to point to the first element.
    */
    QtSoapArrayIterator::QtSoapArrayIterator(QtSoapArray &array)
        : it(array.array.begin()), arr(&array)
    {
    }

    /*!
        Constructs a QtSoapArrayIterator that is a copy of \a copy.
    */
    QtSoapArrayIterator::QtSoapArrayIterator(const QtSoapArrayIterator &copy)
        : it(copy.it), arr(copy.arr)
    {
    }

    /*!
        Returns false if this iterator points to an item in the array, otherwise true.
    */
    bool QtSoapArrayIterator::atEnd() const
    {
        return (it == arr->array.end());
    }

    /*!
        Assignment operator of QtSoapArrayIterator. Makes this iterator a
        copy of \a copy.
    */
    QtSoapArrayIterator &QtSoapArrayIterator::operator =(const QtSoapArrayIterator &copy)
    {
        it = copy.it;
        arr = copy.arr;

        return *this;
    }

    /*!
        Destructs the QtSoapArrayIterator.
    */
    QtSoapArrayIterator::~QtSoapArrayIterator()
    {
    }

    /*!
        \overload

        Returns the ordinal position of the iterator. Works for arrays of
        any dimension, but is only useful for one dimensional arrays.
    */
    int QtSoapArrayIterator::pos() const
    {
        return it.key();
    }

    /*!
        Populates the arguments \a pos0, \a pos1, \a pos2, \a pos3 and \a
        pos4 with the coordinate of the current position of the iterator.
        For a one dimensional array, only \a pos0 is populated. For a two
        dimensional array, \a pos0 and \a pos1 are populated, and so on.

        Any of the arguments that are 0-pointers are ignored.
    */
    void QtSoapArrayIterator::pos(int *pos0, int *pos1, int *pos2,
                      int *pos3, int *pos4) const
    {
        const int key = it.key();

        switch (arr->order) {
        case 1:
        if (pos0) *pos0 = key;
        break;
        case 2: {
        const int tmp = key / arr->siz1;
        if (pos0) *pos0 = tmp;
        if (pos1) *pos1 = key - (tmp * arr->siz1);
        }
        break;
        case 3: {
        const int tmp0 = key / (arr->siz2 * arr->siz1);
        const int tmp1 = key - (tmp0 * (arr->siz2 * arr->siz1));
        const int tmp2 = tmp1 / arr->siz2;
        if (pos0) *pos0 = tmp0;
        if (pos1) *pos1 = tmp2;
        if (pos2) *pos2 = tmp1 - (tmp2 * arr->siz2);
        }
        break;
        case 4: {
        const int tmp0 = key / (arr->siz3 * arr->siz2 * arr->siz1);
        const int tmp1 = key - (tmp0 * (arr->siz3 * arr->siz2 * arr->siz1));
        const int tmp2 = tmp1 / (arr->siz3 * arr->siz2);
        const int tmp3 = tmp1 - (tmp2 * (arr->siz3 * arr->siz2));
        const int tmp4 = tmp3 / arr->siz3;
        const int tmp5 = tmp3 - (tmp4 * arr->siz3);
        if (pos0) *pos0 = tmp0;
        if (pos1) *pos1 = tmp2;
        if (pos2) *pos2 = tmp4;
        if (pos3) *pos3 = tmp5;
        }
        break;
        case 5: {
        const int tmp0 = key / (arr->siz4 * arr->siz3 * arr->siz2 * arr->siz1);
        const int tmp1 = key - (tmp0 * (arr->siz4 * arr->siz3 * arr->siz2 * arr->siz1));
        const int tmp2 = tmp1 / (arr->siz4 * arr->siz3 * arr->siz2);
        const int tmp3 = tmp1 - (tmp2 * (arr->siz4 * arr->siz3 * arr->siz2));
        const int tmp4 = tmp3 / (arr->siz4 * arr->siz3);
        const int tmp5 = tmp3 - (tmp4 * arr->siz4 * arr->siz3);
        const int tmp6 = tmp5 / arr->siz3;
        const int tmp7 = tmp5 - (tmp6 * arr->siz3);
        if (pos0) *pos0 = tmp0;
        if (pos1) *pos1 = tmp2;
        if (pos2) *pos2 = tmp4;
        if (pos3) *pos3 = tmp6;
        if (pos4) *pos4 = tmp7;
        }
        break;
        default:
        break;
        }
    }

    /*!
        Returns a reference to the item that the iterator is currently
        pointing to.
    */
    QtSoapType *QtSoapArrayIterator::data()
    {
        if (it == arr->array.end())
            return 0;
        return it.value().ptr();
    }

    /*!
        Returns a reference to the item that the iterator is currently
        pointing to.
    */
    const QtSoapType *QtSoapArrayIterator::current() const
    {
        if (it == arr->array.end())
            return 0;
        return it.value().ptr();
    }

    /*!
        Moves the iterator position to the next item in the array.
    */
    void QtSoapArrayIterator::operator ++()
    {
        ++it;
    }

    /*!
        Returns true if this Iterator's position is not equal to
        the position of \a j; otherwise returns false.
    */
    bool QtSoapArrayIterator::operator != (const QtSoapArrayIterator &j) const
    {
        return it != j.it;
    }

    /*!
        Returns true if this Iterator's position is equal to the position
        of \a j; otherwise returns false.
    */
    bool QtSoapArrayIterator::operator == (const QtSoapArrayIterator &j) const
    {
        return it == j.it;
    }

    /*!
        Constructs an empty QtSoapStruct.
    */
    QtSoapStruct::QtSoapStruct()
        : QtSoapType(QtSoapQName(), Struct)
    {
    }

    /*!
        Constructs an empty QtSoapStruct and sets its QName (qualified
        name) to \a name.
    */
    QtSoapStruct::QtSoapStruct(const QtSoapQName &name)
        : QtSoapType(name, Struct)
    {
    }

    /*!
        Constructs a QtSoapStruct that is a copy of \a copy.
    */
    QtSoapStruct::QtSoapStruct(const QtSoapStruct &copy)
        : QtSoapType(copy)
    {
        *this = copy;
    }

    /*!
        Destructs the QtSoapStruct.
    */
    QtSoapStruct::~QtSoapStruct()
    {
    }

    /*!
        Removes all items from the struct.
    */
    void QtSoapStruct::clear()
    {
        dict.clear();
    }

    /*!
        Makes this struct a copy of \a copy.
    */
    QtSoapStruct &QtSoapStruct::operator =(const QtSoapStruct &copy)
    {
        if (this == &copy)
            return *this;
        t = copy.t;
        errorStr = copy.errorStr;
        i = copy.i;
        n = copy.n;
        u = copy.u;
        h = copy.h;
        i = copy.i;
        dict = copy.dict;

        return *this;
    }

    /*!
        Inserts the QtSoapType \a item into this struct. Any existing
        item with the same QName (qualified name) will be erased.
    */
    void QtSoapStruct::insert(QtSoapType *item)
    {
        dict.append(item);
    }

    /*!
        Generates the QDomElement representation of this struct.  The
        returned QDomElement is created using \a doc.
    */
    QDomElement QtSoapStruct::toDomElement(QDomDocument doc) const
    {
        QString prefix = QtSoapNamespaces::instance().prefixFor(n.uri());
        QDomElement a = n.uri() == ""
                ? doc.createElement(n.name())
                : doc.createElementNS(n.uri(), prefix + ":" + n.name());

        for (QtSoapStructIterator i(*const_cast<QtSoapStruct *>(this)); i.data(); ++i)
        a.appendChild(i.data()->toDomElement(doc));

        return a;
    }

    /*! \reimp
     */
    bool QtSoapStruct::isValid() const
    {
        return true;
    }

    /*!
        Inspects \a node and constructs the equivalent QtSoapStruct if \a
        node qualifies as a SOAP struct. Returns true if it does;
        otherwise returns false.
    */
    bool QtSoapStruct::parse(QDomNode node)
    {
        if (node.isNull() || !node.isElement())
        return false;

        QDomElement e = node.toElement();
        QDomNodeList children = e.childNodes();
        int c = children.count();
        dict.clear();

        for (int i = 0; i < c; ++i) {
        QDomNode n = children.item(i);
            if (n.isComment())
                continue;
        if (!n.isElement()){
            errorStr = "In the struct element " + e.tagName();
            errorStr += ", the " + QString::number(i) + "th child ";
            errorStr += "is not an element.";
            return false;
        }

        QtSmartPtr<QtSoapType> type = QtSoapTypeFactory::instance().soapType(n.toElement());
        if (!type.ptr()) {
            errorStr = "In the struct element " + e.tagName();
            errorStr += ", child #" + QString::number(i) + ", ";
            errorStr += n.toElement().tagName() + ", was not recognized as a SOAP type.";
            return false;
        }

        dict.append(type);
        }

        setName(QtSoapQName(localName(e.tagName()), e.namespaceURI()));
        return true;
    }

    /*!
        Returns the number of items in this struct.
    */
    int QtSoapStruct::count() const
    {
        return dict.count();
    }

    /*!
        Returns a reference to the item in this struct whose QName
        (qualified name) is \a key. If no such item exists, an empty
        QtSoapType is returned.
    */
    QtSoapType &QtSoapStruct::operator [](const QtSoapQName &key)
    {
        return at(key);
    }

    /*!
        \overload

        Returns a reference to the item in this struct whose QName
        (qualified name) is \a key. If no such item exists, an empty
        QtSoapType is returned.
    */
    const QtSoapType &QtSoapStruct::operator [](const QtSoapQName &key) const
    {
        return at(key);
    }

    /*!
        \overload

        Returns a reference to the item in this struct whose QName
        (qualified name) is \a key. If no such item exists, an empty
        QtSoapType is returned.
    */
    QtSoapType &QtSoapStruct::operator [](const QString &key)
    {
        return at(QtSoapQName(key, ""));
    }

    /*!
        \overload

        Returns a reference to the item in this struct whose QName
        (qualified name) is \a key. If no such item exists, an empty
        QtSoapType is returned.
    */
    const QtSoapType &QtSoapStruct::operator [](const QString &key) const
    {
        return at(QtSoapQName(key, ""));
    }

    /*!
        \overload

        Returns a reference to item number \a i in this struct. If no such
        item exists, an empty QtSoapType is returned.

        The items are ordered in the sequence in which they were inserted,
        starting from 0.
    */
    QtSoapType &QtSoapStruct::operator [](int i)
    {
        static QtSoapType NIL;
        if (i < 0 || i >= dict.count())
            return NIL;

        return *dict[i].ptr();
    }

    /*!
        \overload

        Returns a reference to item number \a i in this struct. If no such
        item exists, an empty QtSoapType is returned.

        The items are ordered in the sequence in which they were inserted,
        starting from 0.
    */
    const QtSoapType &QtSoapStruct::operator [](int i) const
    {
        static QtSoapType NIL;
        if (i < 0 || i >= dict.count())
            return NIL;

        return *dict[i].ptr();
    }

    /*!
        Returns a reference to the item in this struct whose QName
        (qualified name) is \a key. If no such item exists, an empty
        QtSoapType is returned.
    */
    QtSoapType &QtSoapStruct::at(const QtSoapQName &key)
    {
        static QtSoapType NIL;

        QListIterator<QtSmartPtr<QtSoapType> > it(dict);
        while (it.hasNext()) {
            QtSoapType *ret = it.next().ptr();
            if (ret->name() == key)
                return *ret;
        }

        return NIL;
    }

    /*!
        \overload

        Returns a reference to the item in this struct whose QName
        (qualified name) is \a key. If no such item exists, an empty
        QtSoapType is returned.
    */
    const QtSoapType &QtSoapStruct::at(const QtSoapQName &key) const
    {
        static QtSoapType NIL;

        for (QtSoapStructIterator i(*const_cast<QtSoapStruct *>(this)); i.current(); ++i)
        if (i.key() == key)
            return *i.current();

        return NIL;
    }

    /*!
        Constructs a QtSoapStructIterator and initializes it to point to
        the first element in the struct \a s.
    */
    QtSoapStructIterator::QtSoapStructIterator(QtSoapStruct &s) : it(s.dict.begin()), itEnd(s.dict.end())
    {
    }

    /*!
        Destructs the QtSoapStructIterator.
    */
    QtSoapStructIterator::~QtSoapStructIterator()
    {
    }

    /*!
        Returns the QName (qualified name) of the current item.
    */
    QtSoapQName QtSoapStructIterator::key() const
    {
        if (it == itEnd)
            return QtSoapQName();
        return (*it)->name();
    }

    /*!
        Returns a pointer to the current item, or 0 if there is none.
    */
    QtSoapType *QtSoapStructIterator::data()
    {
        if (it == itEnd)
            return 0;
        return it->ptr();
    }

    /*!
        Returns a pointer to the current item, or 0 if there is none.
    */
    const QtSoapType *QtSoapStructIterator::current() const
    {
        if (it == itEnd)
            return 0;
        return it->ptr();
    }

    /*!
        Moves the iterator to the next item in the struct.
    */
    void QtSoapStructIterator::operator ++()
    {
        if (it == itEnd)
            return;
        ++it;
    }

    /*!
        Returns true if this iterator's position is not equal to that of
        \a j; otherwise returns false.
    */
    bool QtSoapStructIterator::operator !=(const QtSoapStructIterator &j) const
    {
        return it != j.it;
    }

    /*!
        Returns true if this iterator's position is equal to that of \a
        j; otherwise returns false.
    */
    bool QtSoapStructIterator::operator ==(const QtSoapStructIterator &j) const
    {
        return it == j.it;
    }

    /*!
        Constructs an empty QtSoapSimpleType.
    */
    QtSoapSimpleType::QtSoapSimpleType()
    {
    }

    /*!
        \overload

        Constructs an empty QtSoapSimpleType, and sets its QName
        (qualified name) to \a name.
    */
    QtSoapSimpleType::QtSoapSimpleType(const QtSoapQName &name)
        : QtSoapType(name)
    {
    }

    /*!
        \overload

        Constructs a QtSoapSimpleType of type Int. Sets its QName
        (qualified name) to \a name and its value to \a n.
    */
    QtSoapSimpleType::QtSoapSimpleType(const QtSoapQName &name, int n)
        : QtSoapType(name, Int), v(QVariant(n))
    {
    }

    /*!
        \overload

        Constructs a QtSoapSimpleType of type Boolean. Sets its QName
        (qualified name) to \a name and its value to \a n.

        \a dummy is an unused variable that should be set to 0; it is
        needed for older compilers that cannot distinguish between bool
        and int.
    */
    QtSoapSimpleType::QtSoapSimpleType(const QtSoapQName &name, bool n, int)
        : QtSoapType(name, Boolean), v(QVariant(n))
    {
    }

    /*!
        \overload

        Constructs a QtSoapSimpleType of type String. Sets its QName
        (qualified name) to \a name and its value to \a n.
    */
    QtSoapSimpleType::QtSoapSimpleType(const QtSoapQName &name, const QString &n)
        : QtSoapType(name, String), v(QVariant(n))
    {
    }

    /*!
        Constructs a QtSoapSimpleType that is a copy of \a copy.
    */
    QtSoapSimpleType::QtSoapSimpleType(const QtSoapSimpleType &copy)
        : QtSoapType(copy), v(copy.v)
    {
    }

    /*!
        Destructs the QtSoapSimpleType.
    */
    QtSoapSimpleType::~QtSoapSimpleType()
    {
    }

    /*!
        Erases the value of this QtSoapSimpleType.
    */
    void QtSoapSimpleType::clear()
    {
        v.clear();
    }

    /*!
        Returns the QDomElement representation of this QtSoapSimpleType.
        The returned QDomElement is created using \a doc.
    */
    QDomElement QtSoapSimpleType::toDomElement(QDomDocument doc) const
    {
        QString prefix = QtSoapNamespaces::instance().prefixFor(n.uri());
        QDomElement a = n.uri() == ""
                ? doc.createElement(n.name())
                : doc.createElementNS(n.uri(), prefix + ":" + n.name());

        QString schemaprefix = QtSoapNamespaces::instance().prefixFor(XML_SCHEMA_INSTANCE);
        a.setAttributeNS(XML_SCHEMA_INSTANCE, schemaprefix + ":type", "xsd:" + typeName());
        a.appendChild(doc.createTextNode(v.toString()));

        return a;
    }

    /*! \reimp
    */
    bool QtSoapSimpleType::isValid() const
    {
        return true;
    }

    /*!
        Makes this QtSoapSimpleType a copy of \a copy.
    */
    QtSoapSimpleType &QtSoapSimpleType::operator =(const QtSoapSimpleType &copy)
    {
        t = copy.t;
        errorStr = copy.errorStr;
        i = copy.i;
        n = copy.n;
        u = copy.u;
        h = copy.h;
        v = copy.v;

        return *this;
    }

    /*!
        Inspects \a node and constructs the QtSoapSimpleType content if \a
        node qualifies as a SOAP simple type. Returns true if it does;
        otherwise returns false.
    */
    bool QtSoapSimpleType::parse(QDomNode node)
    {
        if (node.isNull() || !node.isElement())
        return false;

        QDomElement e = node.toElement();

        QDomAttr typeattr = e.attributeNode("type");
        QString type = typeattr.isNull() ? QString("string") : localName(typeattr.value()).toLower();

        t = QtSoapType::nameToType(type);
        switch (t) {
        case Duration:
        case DateTime:
        case Time:
        case Date:
        case GYearMonth:
        case GYear:
        case GMonthDay:
        case GDay:
        case GMonth:
        case Base64Binary:
        case HexBinary:
        case AnyURI:
        case QName:
        case NOTATION:
        case String:
        case NormalizedString:
        case Token:
        case Language:
        case Name:
        case NMTOKEN:
        case NCName:
        case ID:
        case IDREF:
        case ENTITY:
        v = QVariant(e.text());
        break;
        case Float:
        v = QVariant(e.text().toFloat());
        break;
        case Double:
        v = QVariant(e.text().toDouble());
        break;
        case Decimal:
        case Integer:
        case NonPositiveInteger:
        case NegativeInteger:
        case Long:
        case Int:
        case Short:
        case Byte:
        case NonNegativeInteger:
        case UnsignedLong:
        case PositiveInteger:
        case UnsignedInt:
        case UnsignedShort:
        case UnsignedByte:
        if (e.text() == "" || (e.text() != "" && (e.text()[0].isNumber() || e.text()[0] == '-')))
            v = QVariant(e.text().toInt());
        else {
            errorStr = "Type error at element \"" + e.tagName() + "\"";
            return false;
        }

        break;
        case Boolean: {
        QString val = e.text().trimmed().toLower();
        if (val == "false")
            v = QVariant(false);
        else if (val == "true")
            v = QVariant(true);
        }
        break;
        default:
        v = e.text();
        break;
        }

        setName(QtSoapQName(localName(e.tagName()), e.namespaceURI()));
        return true;
    }

    /*!
        Returns the value of the simple type as a QString.
    */
    QString QtSoapSimpleType::toString() const
    {
        return v.toString();
    }

    /*!
        Returns the value of the simple type as an int.
    */
    int QtSoapSimpleType::toInt() const
    {
        return v.toInt();
    }

    /*!
        Returns the value of the simple type as a bool.
    */
    bool QtSoapSimpleType::toBool() const
    {
        return v.toBool();
    }

    /*!
        Returns the QVariant value of this QtSoapSimpleType.
    */
    QVariant QtSoapSimpleType::value() const
    {
        return v;
    }

    /*! \class QtSoapMessage qtsoap.h
        \brief The QtSoapMessage class provides easy access to SOAP
        messages.

        With this class, you can create and inspect any SOAP message.
        There are convenience functions available for generating the most
        common types of SOAP messages, and any other messages can be
        constructed manually using addBodyItem().

        Use setMethod() and addMethodArgument() to construct a method
        request. The return value of a method response is available
        from returnValue().

        Use setFaultCode(), setFaultString() and addFaultDetail() to
        construct a Fault message. To inspect a Fault message, use
        faultCode(), faultString() and faultDetail().

        To add items to the body part of the SOAP message, use
        addBodyItem(). To add items to the header, use addHeaderItem().

        toXmlString() returns a QString XML representation of the SOAP
        message. clear() resets all content in the message, creating an
        empty SOAP message.

        \code
        QtSoapMessage message;

        message.setMethod("getTemperature", "http://weather.example.com/temperature");
        message.addMethodArgument("city", "Oslo");

        // Get the SOAP message as an XML string.
        QString xml = message.toXmlString();
        \endcode

        QtSoap provides a partial implementation of version 1.1 of the
        SOAP protocol as defined in \l http://www.w3.org/TR/SOAP/.

        \list
        \i Server side SOAP is not supported.
        \i References to values (id and href attributes) are not supported.
        \i Arrays support a maximum of five dimensions.
        \i Namespaces for types are not checked. Only the type names are used.
        \i The encodingStyle attribute is ignored. The serialization and
           encoding rules from section 5 in the SOAP v1.1 specification
           are assumed regardless of the value of the encodingStyle
           attribute.
        \i QtSoapType does not have accessors for attributes, which means
           for example that actor, mustUnderstand and so on are not
           accessible in headers.
        \i The SOAP root attribute is not supported.
        \endlist

        \sa QtSoapType, QtSoapQName, QtSoapHttpTransport

    */

    /*! \enum QtSoapMessage::FaultCode

        This enum describes all the supported SOAP Fault codes:

        \value VersionMismatch
        The namespace for the Envelope element was unrecognized by the
        remote SOAP server. This usually means that the remote server does
        not support version 1.1 of the SOAP protocol.

        \value MustUnderstand
        One of the header items in the SOAP message with a
        "MustUnderstand" attribute was not recognized by the remote
        server.

        \value Client
        An error in the SOAP message or transport prevents further
        processing by the remote SOAP server.

        \value Server
        An error in the remote SOAP server prevents it from processing the
        SOAP message.

        \omitvalue Other
    */

    /*! \enum QtSoapMessage::MessageType

        \value Fault
        \value MethodRequest
        \value MethodResponse
        \value OtherType

    */

    /*!
        Constructs an empty QtSoapMessage. The message only contains the
        Envelope element, with no header and no body.
    */
    QtSoapMessage::QtSoapMessage()
        : type(OtherType), envelope(QtSoapQName("Envelope", SOAPv11_ENVELOPE))
    {
        init();
    }

    /*!
        Constructs a copy of \a copy.
    */
    QtSoapMessage::QtSoapMessage(const QtSoapMessage &copy)
        : type(copy.type), envelope(copy.envelope), m(copy.m), margs(copy.margs),
          errorStr(copy.errorStr)
    {
        init();
    }

    /*!
        Destructs a QtSoapMessage.
    */
    QtSoapMessage::~QtSoapMessage()
    {
    }

    /*! \internal

        Registers the standard SOAP namespaces with prefixes.
    */
    void QtSoapMessage::init()
    {
        QtSoapNamespaces::instance().registerNamespace("SOAP-ENV", SOAPv11_ENVELOPE);
        QtSoapNamespaces::instance().registerNamespace("SOAP-ENC", SOAPv11_ENCODING);
        QtSoapNamespaces::instance().registerNamespace("xsi", XML_SCHEMA_INSTANCE);
        QtSoapNamespaces::instance().registerNamespace("xsd", XML_SCHEMA);
    }

    /*!
        Clears the content of the SOAP message.
    */
    void QtSoapMessage::clear()
    {
        type = OtherType;
        envelope.clear();
        m = QtSoapQName();
        margs.clear();
        errorStr = "Unknown error";
    }

    /*!
        Makes this message a copy of \a copy.
    */
    QtSoapMessage &QtSoapMessage::operator =(const QtSoapMessage &copy)
    {
        envelope = copy.envelope;
        m = copy.m;
        margs = copy.margs;
        errorStr = copy.errorStr;
        return *this;
    }

    /*!
        Imports the QDomDocument \a d if it validates as a SOAP
        message. Any existing message content is replaced.

        If the import fails, this message becomes a Fault message.

        Returns true if the import succeeds, otherwise false.
    */
    bool QtSoapMessage::setContent(QDomDocument &d)
    {
        if (isValidSoapMessage(d)) {
        clear();
            QDomNode node = d.firstChild();
            if (!node.isElement())
                node = node.nextSibling();

        if (envelope.parse(node))
            return true;
        }

        return false;
    }

    /*!
        \overload

        Parses the XML document in \a buffer. Imports the document if it
        validates as a SOAP message. Any existing message content is
        replaced.

        If the import fails, this message becomes a Fault message.

        Returns true if the import succeeds, otherwise false.
    */
    bool QtSoapMessage::setContent(const QByteArray &buffer)
    {
        int errorLine, errorColumn;
        QString errorMsg;

        QDomDocument doc;
        if (!doc.setContent(buffer, true, &errorMsg,
                &errorLine, &errorColumn)) {
        QString s;
        s.sprintf("%s at line %i, column %i", errorMsg.toLatin1().constData(),
              errorLine, errorColumn);
        setFaultCode(VersionMismatch);
        setFaultString("XML parse error");
        addFaultDetail(new QtSoapSimpleType(QtSoapQName("ParseError"), s));
        return false;
        }

        if (!isValidSoapMessage(doc))
        return false;

        QDomNode node = doc.firstChild();
        if (!node.isElement())
        node = node.nextSibling();
        bool res = envelope.parse(node);
        if (!res)
        qDebug("QtSoapMessage::setContent(), parsing failed: %s", envelope.errorString().toLatin1().constData());
        return res;
    }

    /*!
        Validates the QDomDocument \a candidate using some simple
        heuristics. Returns true if the document is a valid SOAP message;
        otherwise returns false.
    */
    bool QtSoapMessage::isValidSoapMessage(const QDomDocument &candidate)
    {
        QDomNode tmp = candidate.firstChild();
        if (tmp.isNull())
        return false;

        // Skip the initial processing instruction if there is one. Most
        // likely this isn't actually a processing instruction, but rather
        // the initial xml declaration <?xml...
        if (tmp.isProcessingInstruction()) {
        tmp = tmp.nextSibling();

        if (tmp.isNull() || !tmp.isElement())
            return false;
        }

        QDomElement tmpe = tmp.toElement();

        if (localName(tmpe.tagName()).toUpper() != "ENVELOPE") {
        setFaultCode(VersionMismatch);
        setFaultString("SOAP structure invalid");
        addFaultDetail(new QtSoapSimpleType(QtSoapQName("extra"), "root element \"" + tmpe.localName()
                        + "\"/\"" + tmpe.tagName() + "\" is not envelope"));
        return false;
        }

        tmp = tmp.firstChild();
        if (tmp.isNull() || !tmp.isElement()) {
        setFaultCode(VersionMismatch);
        setFaultString("SOAP structure invalid");
        addFaultDetail(new QtSoapSimpleType(QtSoapQName("extra"), "mandatory body element missing"));
        return false;
        }

        QDomElement tmpe2 = tmp.toElement();

        bool foundHeader = false;
        if (localName(tmpe2.tagName()).toUpper() == "HEADER") {
        foundHeader = true;
        tmp = tmp.nextSibling();
        }

        if (!foundHeader && (tmp.isNull() || !tmp.isElement())) {
        setFaultCode(VersionMismatch);
        setFaultString("SOAP structure invalid");
        addFaultDetail(new QtSoapSimpleType(QtSoapQName("extra"), "mandatory body element missing"));
        return false;
        }

        QDomElement tmpe3 = tmp.toElement();

        if (localName(tmpe3.tagName()).toUpper() != "BODY") {
        setFaultCode(VersionMismatch);
        setFaultString("SOAP structure invalid");
        addFaultDetail(new QtSoapSimpleType(QtSoapQName("extra"), "mandatory body element missing"));
        return false;
        }

        // At this point, check that the version of the envelope is
        // correct.
        if (tmpe.namespaceURI() != SOAPv11_ENVELOPE) {
        setFaultCode(VersionMismatch);
        setFaultString("SOAP structure invalid");
        addFaultDetail(new QtSoapSimpleType(QtSoapQName("extra"), "Unsupported namespace for envelope element"));
        return false;
        }

        return true;
    }

    /*!
        Returns the XML representation of the SOAP message as a QString,
        optionally indenting using \a indent spaces.
    */
    QString QtSoapMessage::toXmlString(int indent) const
    {
        QDomImplementation impl;
        QDomDocument doc = impl.createDocument(QString(), QString("placeholder"),
                                               QDomDocumentType());
        doc.removeChild(doc.firstChild());
        doc.appendChild(envelope.toDomElement(doc));

        QDomElement env = doc.firstChild().toElement();

        env.setAttribute(QtSoapNamespaces::instance().prefixFor(SOAPv11_ENVELOPE)
                 + ":" + "encodingStyle",
                 SOAPv11_ENCODING);

        env.setAttribute("xmlns:" + QtSoapNamespaces::instance().prefixFor(XML_SCHEMA),
                 XML_SCHEMA);

        return doc.toString(indent);
    }

    /*!
        Returns a human readable explanation of the most recent error that
        occurred in the QtSoapMessage.
    */
    QString QtSoapMessage::errorString() const
    {
        return errorStr;
    }

    /*!
        Adds \a item to the body in the SOAP message. The item is added
        after the last existing item in the body.
    */
    void QtSoapMessage::addBodyItem(QtSoapType *item)
    {
        body().insert(item);
    }

    /*!
        Adds \a item to the header in the SOAP message. The item is added
        after the last existing item in the header.
    */
    void QtSoapMessage::addHeaderItem(QtSoapType *item)
    {
        QtSoapType &headerTmp = envelope[QtSoapQName("Header", SOAPv11_ENVELOPE)];
        if (!headerTmp.isValid())
        envelope.insert(new QtSoapStruct(QtSoapQName("Header", SOAPv11_ENVELOPE)));

        QtSoapStruct &header = (QtSoapStruct &)envelope[QtSoapQName("Header", SOAPv11_ENVELOPE)];
        header.insert(item);
    }
    /*!
        Returns the return value of a SOAP method response as a
        QtSoapType.
    */
    const QtSoapType &QtSoapMessage::returnValue() const
    {
        static QtSoapType NIL;

        const QtSoapType &meth = method();

        if (!meth.isValid() || meth.type() != QtSoapType::Struct)
        return NIL;

        QtSoapStruct &m = (QtSoapStruct &) meth;
        if (m.count() == 0)
        return NIL;

        QtSoapStructIterator mi(m);
        return *mi.data();
    }

    /*!
        Returns the Fault detail element of a SOAP Fault message.
    */
    const QtSoapType &QtSoapMessage::faultDetail() const
    {
        return body()[QtSoapQName("Fault", SOAPv11_ENVELOPE)][QtSoapQName("Detail")];
    }

    /*!
        Returns the Fault faultstring element of a SOAP Fault message.
    */
    const QtSoapType &QtSoapMessage::faultString() const
    {
        return body()[QtSoapQName("Fault", SOAPv11_ENVELOPE)][QtSoapQName("Faultstring")];
    }

    /*!
        Returns true if the message is a SOAP Fault message; otherwise
        returns false.
    */
    bool QtSoapMessage::isFault() const
    {
        return faultCode() != Other;
    }

    /*!
        Returns the Fault faultcode element of a SOAP Fault message.
    */
    QtSoapMessage::FaultCode QtSoapMessage::faultCode() const
    {
        QtSoapType &code = body()[QtSoapQName("Fault")][QtSoapQName("Faultcode")];
        if (!code.isValid() || (code.type() != QtSoapType::String
                                && code.type() != QtSoapType::QName))
        return Other;

        QtSoapSimpleType &fcode = (QtSoapSimpleType &)code;
        QString fcodestr = fcode.value().toString();

        // Only test string before first .
        int pos;
        if ((pos = fcodestr.indexOf('.')) != -1)
            fcodestr.truncate(pos);

        if (localName(fcodestr.toLower()) == "versionmismatch")
        return VersionMismatch;

        if (localName(fcodestr.toLower()) == "mustunderstand")
        return MustUnderstand;

        if (localName(fcodestr.toLower()) == "client")
        return Client;

        if (localName(fcodestr.toLower()) == "server")
        return Server;

        return Other;
    }

    /*!
        Returns a reference to the body of the SOAP message.
    */
    QtSoapStruct &QtSoapMessage::body() const
    {
        const QtSoapQName bodyName("Body", SOAPv11_ENVELOPE);

        QtSoapType &bodyTmp = envelope[bodyName];
        if (!bodyTmp.isValid())
        envelope.insert(new QtSoapStruct(bodyName));

        return (QtSoapStruct &)envelope[bodyName];
    }

    /*!
        Returns a reference to the header of the SOAP message.
    */
    QtSoapStruct &QtSoapMessage::header() const
    {
        const QtSoapQName headerName("Header", SOAPv11_ENVELOPE);

        QtSoapType &headerTmp = envelope[headerName];
        if (!headerTmp.isValid())
        envelope.insert(new QtSoapStruct(headerName));

        return (QtSoapStruct &)envelope[headerName];
    }

    /*!
        Sets the fault code of the SOAP Fault message to \a code.
    */
    void QtSoapMessage::setFaultCode(FaultCode code)
    {
        if (type != Fault && type != OtherType) {
        clear();
        type = Fault;
        }

        if (!body()[QtSoapQName("Fault", SOAPv11_ENVELOPE)].isValid())
        addBodyItem(new QtSoapStruct(QtSoapQName("Fault", SOAPv11_ENVELOPE)));

        QString codeStr;
        switch (code) {
        case VersionMismatch:
        codeStr = "SOAP-ENV:VersionMismatch";
        break;
        case MustUnderstand:
        codeStr = "SOAP-ENV:MustUnderstand";
        break;
        case Client:
        codeStr = "SOAP-ENV:Client";
        break;
        case Server:
        codeStr = "SOAP-ENV:Server";
        break;
        case Other:
        codeStr = "Other";
        break;
        }

        QtSoapType &node = body()[QtSoapQName("Fault", SOAPv11_ENVELOPE)];
        QtSoapStruct &fault = reinterpret_cast<QtSoapStruct &>(node);
        fault.insert(new QtSoapSimpleType(QtSoapQName("Faultcode"), codeStr));
    }

    /*!
        Sets the Fault faultstring of the SOAP Fault message to \a s.
    */
    void QtSoapMessage::setFaultString(const QString &s)
    {
        if (type != Fault && type != OtherType) {
        clear();
        type = Fault;
        }

        if (!body()[QtSoapQName("Fault", SOAPv11_ENVELOPE)].isValid())
        addBodyItem(new QtSoapStruct(QtSoapQName("Fault", SOAPv11_ENVELOPE)));

        QtSoapType &node = body()[QtSoapQName("Fault", SOAPv11_ENVELOPE)];
        QtSoapStruct &fault = reinterpret_cast<QtSoapStruct &>(node);
        fault.insert(new QtSoapSimpleType(QtSoapQName("Faultstring"), s));
    }

    /*!
       Adds the QtSoapType \a detail to the end of the list of faultdetail
       items in a SOAP Fault message.
    */
    void QtSoapMessage::addFaultDetail(QtSoapType *detail)
    {
        if (type != Fault && type != OtherType) {
        clear();
        type = Fault;
        }

        if (!body()[QtSoapQName("Fault", SOAPv11_ENVELOPE)].isValid())
        addBodyItem(new QtSoapStruct(QtSoapQName("Fault", SOAPv11_ENVELOPE)));

        QtSoapType &node = body()[QtSoapQName("Fault", SOAPv11_ENVELOPE)];
        QtSoapStruct &fault = reinterpret_cast<QtSoapStruct &>(node);
        if (!fault[QtSoapQName("Faultdetail", SOAPv11_ENVELOPE)].isValid())
        fault.insert(new QtSoapStruct(QtSoapQName("Faultdetail", SOAPv11_ENVELOPE)));

        QtSoapType &node2 = fault[QtSoapQName("Faultdetail", SOAPv11_ENVELOPE)];
        QtSoapStruct &fdetail = reinterpret_cast<QtSoapStruct &>(node2);

        fdetail.insert(detail);
    }

    /*!
        Returns the method of a SOAP method request or response
        as a QtSoapType.
    */
    const QtSoapType &QtSoapMessage::method() const
    {
        static QtSoapType NIL;

        if (body().count() == 0)
        return NIL;

        QtSoapStructIterator it(body());

        return *it.data();
    }

    /*!
        Sets the QName (qualified name) of the method to call in a SOAP
        method request to \a meth.

        This function must be called before calling
        addMethodArgument().
    */
    void QtSoapMessage::setMethod(const QtSoapQName &meth)
    {
        if (type != MethodRequest && type != OtherType) {
        clear();
        type = MethodRequest;
        }

        addBodyItem(new QtSoapStruct(meth));
    }

    /*! \overload

        Sets the method name to \a name and uri to \a uri.
    */
    void QtSoapMessage::setMethod(const QString &name, const QString &uri)
    {
        setMethod(QtSoapQName(name, uri));
    }

    /*!
       Adds argument \a arg to the list of arguments that are passed in a
       SOAP method request.

       \warning setMethod() must be called before calling this function.
    */
    void QtSoapMessage::addMethodArgument(QtSoapType *arg)
    {
        if (body().count() == 0) {
        qWarning("Attempted to add argument (%s:%s) without first setting method",
             arg->name().uri().toLatin1().constData(), arg->name().name().toLatin1().constData());
        return;
        }

        QtSoapStructIterator it(body());
        QtSoapType &node = *it.data();
        QtSoapStruct &meth = static_cast<QtSoapStruct &>(node);
        meth.insert(arg);
    }

    /*! \overload

        Adds an argument called \a name with a uri of \a uri. The type
        of the argument is QtSoapType::String and its value is \a value.
    */
    void QtSoapMessage::addMethodArgument(const QString &name, const QString &uri, const QString &value)
    {
        addMethodArgument(new QtSoapSimpleType(QtSoapQName(name, uri), value));
    }

    /*! \overload

        Adds an argument called \a name with a uri of \a uri. The type
        of the argument is QtSoapType::Boolean and its value is \a value.

        The \a dummy argument is used to distinguish this function from
        the overload which takes an int.
    */
    void QtSoapMessage::addMethodArgument(const QString &name, const QString &uri, bool value, int dummy)
    {
        addMethodArgument(new QtSoapSimpleType(QtSoapQName(name, uri), value, dummy));
    }

    /*! \overload

        Adds an argument called \a name with a uri of \a uri. The type
        of the argument is QtSoapType::Integer and its value is \a value.
    */
    void QtSoapMessage::addMethodArgument(const QString &name, const QString &uri, int value)
    {
        addMethodArgument(new QtSoapSimpleType(QtSoapQName(name, uri), value));
    }

    /*!
        Constructs a QtSoapTypeFactory and initializes it with all the
        known SOAP types.
    */
    QtSoapTypeFactory::QtSoapTypeFactory()
    {
        QtSoapTypeConstructor<QtSoapStruct> *structConstructor = new QtSoapTypeConstructor<QtSoapStruct>();
        deleteList.append(structConstructor);
        QtSoapTypeConstructor<QtSoapArray> *arrayConstructor = new QtSoapTypeConstructor<QtSoapArray>();
        deleteList.append(arrayConstructor);
        QtSoapTypeConstructor<QtSoapSimpleType> *basicTypeConstructor = new QtSoapTypeConstructor<QtSoapSimpleType>();
        deleteList.append(basicTypeConstructor);

        registerHandler("struct", structConstructor);
        registerHandler("array", arrayConstructor);
        registerHandler("string", basicTypeConstructor);
        registerHandler("normalizedstring", basicTypeConstructor);
        registerHandler("token", basicTypeConstructor);
        registerHandler("language", basicTypeConstructor);
        registerHandler("name", basicTypeConstructor);
        registerHandler("ncname", basicTypeConstructor);
        registerHandler("id", basicTypeConstructor);
        registerHandler("idref", basicTypeConstructor);
        registerHandler("entity", basicTypeConstructor);
        registerHandler("nmtoken", basicTypeConstructor);
        registerHandler("nmtokens", basicTypeConstructor);
        registerHandler("boolean", basicTypeConstructor);
        registerHandler("decimal", basicTypeConstructor);
        registerHandler("integer", basicTypeConstructor);
        registerHandler("nonpositiveinteger", basicTypeConstructor);
        registerHandler("negativeinteger", basicTypeConstructor);
        registerHandler("int", basicTypeConstructor);
        registerHandler("long", basicTypeConstructor);
        registerHandler("short", basicTypeConstructor);
        registerHandler("byte", basicTypeConstructor);
        registerHandler("nonnegativeinteger", basicTypeConstructor);
        registerHandler("unsignedlong", basicTypeConstructor);
        registerHandler("unsignedint", basicTypeConstructor);
        registerHandler("unsignedshort", basicTypeConstructor);
        registerHandler("unsignedbyte", basicTypeConstructor);
        registerHandler("positiveinteger", basicTypeConstructor);
        registerHandler("float", basicTypeConstructor);
        registerHandler("double", basicTypeConstructor);
        registerHandler("other", structConstructor);
    }

    /*!
        Destructs the QtSoapTypeFactory. This destructor is called when
        the application exits.
    */
    QtSoapTypeFactory::~QtSoapTypeFactory()
    {
        QLinkedList<QtSoapTypeConstructorBase*>::ConstIterator it = deleteList.begin();
        while (it != deleteList.end()) {
            delete *it;
            ++it;
        }
    }

    /*!
        Returns a reference to the QtSoapTypeFactory singleton.
    */
    QtSoapTypeFactory &QtSoapTypeFactory::instance()
    {
        static QtSoapTypeFactory factory;
        return factory;
    }

    /*!
        Registers a handler \a handler for a QtSoapType called \a name.
    */
    bool QtSoapTypeFactory::registerHandler(const QString &name, QtSoapTypeConstructorBase *handler)
    {
        if (typeHandlers.find(name) != typeHandlers.end()) {
        errorStr = "A handler for " + name + " is already registered.";
        return false;
        }

        typeHandlers.insert(name, handler);
        return true;
    }

    /*! \internal
    */
    QtSmartPtr<QtSoapType> QtSoapTypeFactory::soapType(QDomNode node) const
    {
        if (node.isNull() || !node.isElement())
        return QtSmartPtr<QtSoapType>();

        QDomElement elem = node.toElement();

        QDomAttr attr = elem.attributeNode("type");
        QtSoapTypeConstructorBase *constructor = 0;
        if (!attr.isNull()) {
            QHash<QString, QtSoapTypeConstructorBase *>::ConstIterator it;
        it = typeHandlers.find(localName(attr.value().toLower()));
            if (it != typeHandlers.end())
                constructor = *it;
        }

        if (attr.isNull() || !constructor) {
            QHash<QString, QtSoapTypeConstructorBase *>::ConstIterator it;
        if (node.firstChild().isElement()) {
                if (localName(node.nodeName().toLower()) == "array") {
                    it = typeHandlers.find("array");
                } else
                    it = typeHandlers.find("struct");
            } else
            it = typeHandlers.find("string");
            if (it != typeHandlers.end())
                constructor = *it;
        }

        if (!constructor) {
        return QtSmartPtr<QtSoapType>();
        }

        QtSoapType *type = constructor->createObject(node);

        if (!type)
        errorStr = constructor->errorString();

        return QtSmartPtr<QtSoapType>(type);
    }

    /*!
        Returns a human readable interpretation of the last error
        that occurred.
    */
    QString QtSoapTypeFactory::errorString() const
    {
        return errorStr;
    }

    /*! \class QtSoapHttpTransport

        \brief The QtSoapHttpTransport class provides a mechanism for
        transporting SOAP messages to and from other hosts using the
        HTTP protocol.

        Use this class to submit SOAP messages to a web service.
        Set the hostname of the SOAP server with setHost(). Some servers
        also require the SOAPAction header to be set, and you can do this
        with setAction(). Next, submit the request with submitRequest(),
        passing the message to submit together with the path that you want
        to submit the message to. The responseReady() signal is emitted
        when a response has been received. Call getResponse() to get the
        reponse from the service.

        QtSoapHttpTransport usage example: If a SOAP weather service was
        running on the host weather.example.com, the following code might
        be used to find the temperature in any given city:

        \code
        void WeatherFetcher::findTemperature(const QString &city)
        {
            QtSoapMessage message;
            message.setMethod("getTemperature", "http://weather.example.com/temperature");
            message.setMethodArgument("city", "", city);

            // transport is a private member of WeatherFetcher, of type QtSoapHttpTransport
            transport.setHost("www.example.com");
            connect(&transport, SIGNAL(responseReady()), SLOT(readResponse()));

            transport.submitRequest(message, "/weatherfetcher/fetch.asp");
        }
        \endcode

        This is an example implementation of the readResponse() slot in
        the WeatherFetcher class:

        \code
        void WeatherFetcher::readResponse()
        {
            const QtSoapMessage &response = transport.getResponse();
            if (response.isFault()) {
                cout << response.faultString().toString().toLatin1().constData() << endl;
                return;
            }

            const QtSoapType &returnValue = response.returnValue();
            if (returnValue["temperature"].isValid()) {
            cout << "The current temperature is "
                 << returnValue["temperature"].toString().toLatin1().constData()
                 << " degrees Celcius." << endl;
        }
        \endcode

        \sa QtSoapMessage, QtSoapType
    */

    /*! \fn void QtSoapHttpTransport::responseReady()

        This signal is emitted when a SOAP response is received from a
        remote peer.

        \sa getResponse()
    */

    /*! \fn void QtSoapHttpTransport::responseReady(const QtSoapMessage &response)

        This signal is emitted when a SOAP response is received from a
        remote peer. The received response is available in \a
        response. This signal is emitted in tandem with the argument-less
        responseReady() signal.

        \sa responseReady()
    */

    /*!
        Constructs a QtSoapHttpTransport object. Passes \a parent to
        QObject's constructor.
    */

    QtSoapHttpTransport::QtSoapHttpTransport(QObject *parent)
        : QObject(parent), networkMgr(this)
    {
        bool ok = connect(&networkMgr, SIGNAL(finished(QNetworkReply *)),
                          SLOT(readResponse(QNetworkReply *)));
        Q_ASSERT(ok);
        Q_UNUSED(ok);
    }

    /*!
        Destructs a QtSoapHttpTransport.
    */
    QtSoapHttpTransport::~QtSoapHttpTransport()
    {
    }

    /*!
      \obsolete
    */

    void QtSoapHttpTransport::setHost(const QString &host, int port)
    {
        setHost(host, false, port);
    }

    /*!
      Sets the \a host this transport should connect to. The transport
      mode will be HTTP, unless \a useSecureHTTP is set, in which case it
      will be HTTPS. This transport will connect to the well-known ports
      by default (80 for HTTP, 443 for HTTPS), unless a different,
      non-zero port is specified in \a port.
    */
    void QtSoapHttpTransport::setHost(const QString &host, bool useSecureHTTP, int port)
    {
        url.setHost(host);
        url.setScheme(useSecureHTTP ? QLatin1String("https") : QLatin1String("http"));
        if (port)
            url.setPort(port);
        else
            url.setPort(useSecureHTTP ? 443 : 80);
    }

    /*!
        Sets the HTTP header SOAPAction to \a action.
    */
    void QtSoapHttpTransport::setAction(const QString &action)
    {
        soapAction = action;
    }

    /*!
        Submits the SOAP message \a request to the path \a path on the
        HTTP server set using setHost().
    */
    void QtSoapHttpTransport::submitRequest(QtSoapMessage &request, const QString &path)
    {
        QNetworkRequest networkReq;
        networkReq.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("text/xml;charset=utf-8"));
        networkReq.setRawHeader("SOAPAction", soapAction.toAscii());
        url.setPath(path);
        networkReq.setUrl(url);

        soapResponse.clear();
        networkRep = networkMgr.post(networkReq, request.toXmlString().toUtf8().constData());
    }

    /*!
        Returns the most recently received response SOAP message. This
        message could be a Fault message, so it is wise to check using
        QtSoapMessage::isFault() before processing the response.
    */
    const QtSoapMessage &QtSoapHttpTransport::getResponse() const
    {
        return soapResponse;
    }

    /*!
        Returns a pointer to the QNetworkAccessManager object used by this
        transport. This is useful if the application needs to connect to its
        signals, or set or read its cookie jar, etc.
    */

    QNetworkAccessManager *QtSoapHttpTransport::networkAccessManager()
    {
        return &networkMgr;
    }

    /*!
        Returns a pointer to the QNetworkReply object of the current (or last)
        request, or 0 if no such object is currently available.

        This is useful if the application needs to access the raw header
        data etc.
    */

    QNetworkReply *QtSoapHttpTransport::networkReply()
    {
        return networkRep;
    }

    /*!

    */

    void QtSoapHttpTransport::readResponse(QNetworkReply *reply)
    {
        networkRep = reply;
        switch (reply->error()) {
        case QNetworkReply::NoError:
        case QNetworkReply::ContentAccessDenied:
        case QNetworkReply::ContentOperationNotPermittedError:
        case QNetworkReply::ContentNotFoundError:
        case QNetworkReply::UnknownContentError:
            {
                soapResponse.setContent(reply->readAll());

                int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
                if (httpStatus != 200 && httpStatus != 100) {
                    if (soapResponse.faultCode() == QtSoapMessage::Other)
                        soapResponse.setFaultCode(QtSoapMessage::Client);
                    /*
                    QString httpReason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
                    soapResponse.setFaultString(QString("HTTP status %2 (%3).\n%1").arg(soapResponse.faultString().toString()).arg(httpStatus).arg(httpReason));
                    */
                }
            }
            break;
        default:
            {
                soapResponse.setFaultCode(QtSoapMessage::Client);
                soapResponse.setFaultString(QString("Network transport error (%1): %2").arg(reply->error()).arg(reply->errorString()));
            }
            break;
        }

        emit responseReady();
        emit responseReady(soapResponse);

        reply->deleteLater();
    }

    /*! \class QtSoapNamespaces qtsoap.h

        \brief The QtSoapNamespaces class provides a registry for XML
        namespaces and prefixes for use in QtSoap.

        When a QtSoapMessage is converted to XML via
        QtSoapMessage::toXmlString(), this class is used to find
        appropriate XML namespace prefixes for the QNames (qualified
        names) in the message.

        To register a namespace with a prefix, call register().
        prefixFor() will then return the prefix that is registered for the
        given namespace, if any.

        To access the QtSoapNamespaces registry, call
        QtSoapNamespaces::instance().

        \code
        QtSoapNamespaces &registry = QtSoapNamespaces::instance();

        registry.register("pre", "http://www.example.com/");
        QString prefix = registry.prefixFor("http://www.example.com/"); // returns "pre"
        \endcode

        \sa QtSoapMessage
    */

    /*!
        Returns a reference to the QtSoapNamespaces singleton.
    */
    QtSoapNamespaces &QtSoapNamespaces::instance()
    {
        static QtSoapNamespaces ns;
        return ns;
    }

    /*! \internal

        Constructs a QtSoapNamespaces object.
    */
    QtSoapNamespaces::QtSoapNamespaces()
    {
    }

    /*!
        Registers the namespace \a uri with the prefix \a prefix.
    */
    void QtSoapNamespaces::registerNamespace(const QString &prefix, const QString &uri)
    {
        namespaces.insert(uri, prefix);
    }

    /*!
        Returns the prefix for the namespace \a uri, or an empty string if
        no prefix has been registered for \a uri.
    */
    QString QtSoapNamespaces::prefixFor(const QString &uri)
    {
        return namespaces.value(uri);
    }