protected function loadParagraphStructure( DOMElement $paragraphNode,
                                               ZipArchive $zip,
                                               array $domains,
                                               $dbSchema,
                                               &$offset = 1)
    {
        $offset     = ( (int) $offset ) ?: 1;
        $structure  = array(
            'id'            => $paragraphNode->getAttribute( 'id' ),
            'type'          => $paragraphNode->getAttribute( 'type' ),
            'name'          => $paragraphNode->hasAttribute( 'name' )
                             ? $paragraphNode->getAttribute( 'name' )
                             : null,
            'left'          => $offset,
            'right'         => ++$offset,
            'properties'    => array(),
            'children'      => array(),
        );

        foreach ( $paragraphNode->childNodes as $child )
        {
            if ( $child instanceof DOMElement )
            {
                switch ( $child->tagName )
                {
                    case 'paragraph':
                        $structure['children'][] = $this->loadParagraphStructure(
                            $child,
                            $zip,
                            $domains,
                            $dbSchema,
                            $offset
                        );

                        $structure['right'] = ++$offset;
                        break;

                    case 'paragraph-property':
                        $substitutions = array();

                        foreach ( $child->childNodes as $substitutionNode )
                        {
                            if ( $substitutionNode instanceof DOMElement &&
                                 $substitutionNode->tagName === 'substitution' )
                            {
                                $name   = $substitutionNode->getAttribute( 'original' );
                                $value  = $substitutionNode->getAttribute( 'file' );
                                $substitutions[$name] = $value;
                            }
                        }

                        $value = $this->processValue(
                            $child->getAttribute( 'value' ),
                            $zip,
                            $substitutions,
                            $domains,
                            $dbSchema
                        );

                        $structure['properties'][] = array(
                            'name'      => $child->getAttribute( 'name' ),
                            'locale'    => ( $child->getAttribute( 'locale' ) ?: '*' ),
                            'value'     => $value,
                        );
                        break;
                }
            }
        }

        return $structure;
    }