0

次の構造のxmlがあります。

<?xml version="1.0"?>
<ONIXMessage xmlns="http://test.com/test">
 ...data...
</ONIXMessage>

xmlns 属性を独自の値に変更する必要があります。どうすればいいですか?できればDOMDocumentクラスを使用してください。

4

1 に答える 1

2

xmlns 属性を独自の値に変更する必要があります。どうすればいいですか?できればDOMDocumentクラスで。

これは設計上不可能です。すべてDOMDocumentに単一のルート/ドキュメント要素があります。

あなたの例のXMLでは、ルート要素は次のとおりです。

{http://test.com/test}ONIXMessage

要素名は、名前空間 URI を先頭に山かっこで囲んで配置するという規則に従って、展開された名前として記述します。

展開された名前全体を示す形式で要素名を記述することは、ここで属性の値を変更したいだけでなく、特定の要素の名前空間 URI を変更したいことも示しています。したがって、要素名を変更します。また、子が同じ名前空間にある場合は、それに含まれるすべての子要素名も含まれる可能性があります。

xmlns属性は要素自体の名前空間 URI のみを反映するため、変更することはできません。で設定するとDOMDocument変更できません。

要素全体を置き換えることはできますが、その場合、子の名前空間も変更されません。これは、textnode の子 (名前空間化されていない) のみを持つ、あなたのものに似た XML の例です。

$xml = <<<EOD
<?xml version="1.0"?>
<ONIXMessage xmlns="uri:old">
 ...data...
</ONIXMessage>
EOD;

$doc = new DOMDocument();
$doc->loadXML($xml);
$newNode = $doc->createElementNS('uri:new', $doc->documentElement->tagName);
$oldNode = $doc->replaceChild($newNode, $doc->documentElement);

foreach(iterator_to_array($oldNode->childNodes, true) as $child) {
    $doc->documentElement->appendChild($child);
}

結果の XML 出力は次のとおりです。

<?xml version="1.0"?>
<ONIXMessage xmlns="uri:new">
 ...data...
</ONIXMessage>

入力XMLを次のような子を含むものに変更します

<?xml version="1.0"?>
<ONIXMessage xmlns="uri:old">
   <data>
     ...data...
   </data>
</ONIXMessage>

次に、次の出力を作成します。ここで再びポップアップする古い名前空間 URI に注意してください。

<?xml version="1.0"?>
<ONIXMessage xmlns="uri:new">
   <default:data xmlns:default="uri:old">
     ...data...
   </default:data>
</ONIXMessage>

ご覧のとおりDOMDocument、既存の要素の名前空間 URI をすぐに置き換える機能は提供されていません。しかし、うまくいけば、これまでにこの回答で提供された情報により、その属性値が既に存在する場合にその属性値を変更できない理由がより明確になります。

libxml ベースの PHP 拡張機能のexpat ベースのパーサーでは、属性であるかどうかに関係なく、既存の属性値を「変更」xmlns*できます。これは、データを解析するだけで、その場で処理できるためです。

実際の例は次のとおりです。

$xml = <<<EOD
<?xml version="1.0" encoding="utf-8"?>
<ONIXMessage xmlns="uri:old">
  <data>
    ...data...
  </data>
</ONIXMessage>
EOD;

$uriReplace = [
    'uri:old' => 'uri:new',
];

$parser = xml_parser_create('UTF-8');
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_set_default_handler($parser, function ($parser, $data) {
    echo $data;
});
xml_set_element_handler($parser, function ($parser, $name, $attribs) use ($xml, $uriReplace) {
    $selfClosing = '/>' === substr($xml, xml_get_current_byte_index($parser), 2);
    echo '<', $name;
    foreach ($attribs as $name => $value) {
        if (substr($name, 0, 5) === 'xmlns' && isset($uriReplace[$value])) {
            $value = $uriReplace[$value];
        }
        printf(' %s="%s"', $name, htmlspecialchars($value, ENT_COMPAT | ENT_XML1));
    }
    echo $selfClosing ? '/>' : '>';
}, function ($parser, $name) use ($xml) {
    $selfClosing = '/>' === substr($xml, xml_get_current_byte_index($parser) - 2, 2);
    if ($selfClosing) return;
    echo '</', $name, '>';
});

xml_parse($parser, $xml, true);
xml_parser_free($parser);

出力では、名前空間 URI が からuri:oldに透過的に変更されていuri:newます。

<ONIXMessage xmlns="uri:new">
   <data>
     ...data...
   </data>
</ONIXMessage>

この例が示すように、XML で使用する各 XML 機能は、パーサーで処理する必要があります。たとえば、XML 宣言がありません。ただし、これらは、欠落しているハンドラー クラスバックを実装することによって (例: CDATA セクションの場合)、または欠落している出力を出力することによって (例: 「欠落している」XML 宣言の場合) 追加できます。これが役に立ち、変更を意図していないこれらの値を変更する別の方法を示してくれることを願っています。

于 2013-03-04T01:30:13.820 に答える