PHP: XMLWriter создает недопустимое объявление пространства имен

XMLWriter кажется неработающим, поскольку он создает объявления пространств имен, которые приводят к неправильному формату экземпляра.

Например:

$writer = new XMLWriter();
$writer->openUri( 'php://output' );

$writer->startIndent( true );
$writer->setIndentString ( "\t" );
$writer->startDocument( '1.0', 'UTF-8' );

$writer->startElement( 'root' );
$writer->writeAttributeNs( 'xmlns', 'bar', 'http://www.w3.org/2000/xmlns/', 'http://example.com' );
$writer->startElementNs( 'bar', 'baz', null );
$writer->endElement();

производит

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:bar="http://example.com" xmlns:xmlns="http://www.w3.org/2000/xmlns/">
    <bar:baz/>
</root>

Обратите внимание на xmlns:xmlns="http://www.w3.org/2000/xmlns/", который:

  1. нигде в PHP-коде, который я написал
  2. нарушает ограничение пространства имен: зарезервированные префиксы и имена пространств имен

Независимо от того, что я делаю, если я создаю любое объявление пространства имен, XMLWriter выводит это недопустимое объявление пространства имен (в дополнение к объявлениям пространств имен, которые я хочу вывести).

Что мне не хватает? Потому что, как есть, это делает XMLWriter непригодным для использования.

Редактировать: Если это имеет значение, я использую PHP 5.4.16 и libxml2 2.7.8.


person Paul 'Sparrow Hawk' Biron    schedule 18.06.2017    source источник


Ответы (1)


Я нашел обходной путь: для создания decls пространства имен просто используйте:

$writer->writeAttribute( 'xmlns:prefix', 'http://example.com' );

Итак, я полагаю, что проблема просто в недостатке документации по этому вопросу в Руководстве по PHP.

Кстати, пример кода в моем вопросе был упрощением кода, который я на самом деле пишу, который реализует простое преобразование экземпляра с использованием XMLReader и XMLWriter, например:

$reader = new XMLReader();
$reader->open( $file );

$writer = new XMLWriter();
$writer->openUri( "{$file}-xformed.xml" );
$writer->setIndent( true );
$writer->setIndentString( "\t" );
$writer->startDocument( '1.0', 'UTF-8' );

while ( $reader->read() ) {
    switch ( $reader->nodeType ) {
        case XMLReader::ELEMENT:
            if ( '' === $reader->namespaceURI ) {
                $writer->startElement( $reader->localName );
            }
            else {
                $writer->startElementNS( $reader->prefix, $reader->localName, $reader->namespaceURI );
            }

            if ( $reader->hasAttributes ) {
                while ( $reader->moveToNextAttribute() ) {
                    if ( '' === $reader->namespaceURI ) {
                        $writer->writeAttribute( $reader->name, $reader->value );
                    }
                    else {
                        // this stmt was causing the illegal namespace decls
                        // even tho there is nothing wrong with the code :-(
                        $writer->writeAttributeNS( $reader->prefix, $reader->localName, $reader->namespaceURI, $reader->value );
                    }
                }
            }

            break;

        // other case stmts for other node types
    }
}

Итак, я просто заменил «цикл атрибутов» на:

            if ( $reader->hasAttributes ) {
                while ( $reader->moveToNextAttribute() ) {
                    if ( in_array( $reader->namespaceURI, array( '', 'http://www.w3.org/2000/xmlns/' ) ) {
                        // create an attribute in the empty namespace or a namespace decl
                        $writer->writeAttribute( $reader->name, $reader->value );
                    }
                    else {
                        // create a namespace-qualified attribute
                        $writer->writeAttributeNS( $reader->prefix, $reader->localName, $reader->namespaceURI, $reader->value );
                    }
                }
            }
person Paul 'Sparrow Hawk' Biron    schedule 18.06.2017