protected static function parseXml( $xmlFile )
    {
        $reader = new \XMLReader();

        // Use custom error handling to suppress warnings and errors during
        // parsing.
        $libXmlErrors = libxml_use_internal_errors( true );

        // Try to open configuration file, and throw parsing exception if
        // something fails.
        $errors = array();

        // Just open, errors will not occure before actually reading.
        if ( !$reader->open( $xmlFile ) )
        {
            throw new XmlParserException( $xmlFile, array() );
        }

        // Current node, processed. Start with a reference to th root node.
        $current = $root = new Document();

        // Stack of parents for the current node. We store this list, because
        // we do not want to store a parent node reference in the nodes, as
        // this breaks with var_export'ing those structures.
        $parents = array( $root );

        // Start processing the XML document
        //
        // The read method may issue warning, even if
        // libxml_use_internal_errors was set to true. That sucks, and we need
        // to use the @ here...
        while( @$reader->read() )
        {
            switch( $reader->nodeType )
            {
                case \XMLReader::ELEMENT:
                    // A new element, which results in a new configuration node as
                    // a child of the current node
                    //
                    // Get name of new element
                    $nodeName = $reader->name;

                    // We create a new object, so append the current node as
                    // future parent node to the parent stack.
                    array_push( $parents, $current );

                    // Create new child and reference node as current working
                    // node
                    $current = $current->$nodeName = new Node();

                    // After reading the elements we need to know about this
                    // for further progressing
                    $emptyElement = $reader->isEmptyElement;

                    // Process elements attributes, if available
                    if ( $reader->hasAttributes )
                    {
                        // Read all attributes and store their values in the
                        // current configuration node
                        while( $reader->moveToNextAttribute() )
                        {
                            $current[$reader->name] = $reader->value;
                        }
                    }

                    if ( !$emptyElement )
                    {
                        // We only break for non empty elements.
                        //
                        // For empty elements the element may also be counted
                        // as a closing tag, so that we want also process the
                        // next case statement.
                        break;
                    }

                case \XMLReader::END_ELEMENT:
                    // At the end of a element set the current pointer back to its
                    // parent
                    //
                    // Pop new current node from parents stack
                    $current = array_pop( $parents );
                    break;

                case \XMLReader::TEXT:
                case \XMLReader::CDATA:
                    // Text and CData node are added as node content.
                    //
                    // Append string, in case several text or Cdata nodes exist
                    // in one node
                    $current->setContent( (string) $current . $reader->value );
                    break;

                // Everything else can be ignored for now..
            }
        }

        // Check if errors occured while reading configuration
        if ( count( $errors = libxml_get_errors() ) )
        {
            // Reset libxml error handling to old state
            libxml_use_internal_errors( $libXmlErrors );
            libxml_clear_errors();

            throw new XmlParserException( $xmlFile, $errors );
        }

        // Reset libxml error handling to old state
        libxml_use_internal_errors( $libXmlErrors );
        return $root->skipRoot();
    }