使用PHP设置XML标记的命名空间


Set the namespace for an XML tag with PHP

我想创建一个具有特定格式的XML文档。它应该看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<ram:FLOW xmlns:ram='"http://MY_LIBRARY'" xmlns:mar='"http://ANOTHER_LIBRARY'" xmlns:xsi='"http://www.w3.org/2001/XMLSchema-instance'">
<Header>
<Source>Application1</Source>
<Time>2014-11-12T12:46:39</Time>
<Environment>TEST</Environment>
<Sequence>537</Sequence>
</Header>
<Data>
<mar:OC_DC>
<DC_elements>
<Unit>
<Unit_ID>089789</Unit_ID>
<State>active</State>
</Unit>
<Unit>
<Unit_ID>459008</Unit_ID>
<State>inactive</State>
</Unit>
</DC_elements>
</mar:OC_DC>
</Data>
</ram:FLOW>

我写了一个PHP/MMySQL脚本来生成这个文档:

<?php   
$xml = new SimpleXMLElement("<?xml version='"1.0'" encoding='"UTF-8'"?><ram:FLOW xmlns:ram='"http://MY_LIBRARY'" xmlns:mar='"http://ANOTHER_LIBRARY'" xmlns:xsi='"http://www.w3.org/2001/XMLSchema-instance'"></ram:FLOW>");
$header = $xml->addChild('Header');
$header->addChild('Source', $source);
$header->addChild('Time', $time);
$header->addChild('Environment', $env);
$header->addChild('Sequence', $sequence);
$data=$xml->addChild('Data');
$mar_oc_dc=$data->addChild('mar:OC_DC');
$dc_elements=$mar_oc_dc->addChild('DC_elements');
while($condition)
{
   // some MySQL code here to extract unit_id and state
   $unit=$dc_elements->addChild('Unit');
   $unit_id=$unit->addChild('Unit_ID', $unit_id);
   $state=$unit->addChild('State', $state);
}
$dom = new DOMDocument();
$dom->preserveWhiteSpace = FALSE;
$dom->formatOutput = TRUE;
$dom->loadXML($xml->asXML());
$handle = fopen("backup/" . $file_name . ".xml", "w");
fwrite($handle, $dom->saveXML());
fclose($handle);            
?>

但结果与我预期的有点不同:

<?xml version="1.0" encoding="UTF-8"?>
<FLOW xmlns:ram='"http://MY_LIBRARY'" xmlns:mar='"http://ANOTHER_LIBRARY'"     xmlns:xsi='"http://www.w3.org/2001/XMLSchema-instance'">
<Header>
<Source>Application1</Source>
<Time>2014-11-12T12:46:39</Time>
<Environment>TEST</Environment>
<Sequence>537</Sequence>
</Header>
<Data>
<OC_DC>
<DC_elements>
<Unit>
<Unit_ID>089789</Unit_ID>
<State>active</State>
</Unit>
<Unit>
<Unit_ID>459008</Unit_ID>
<State>inactive</State>
</Unit>
</DC_elements>
</OC_DC>
</Data>
</FLOW>

如您所见,ram:FLOW标记变为FLOWmar:OC_DC标签变为OC_DC。我在Stack Overflow和其他网站上寻找解决方案,但没有找到。你能帮我一下吗?

提前谢谢。

xmlns:*属性是命名空间定义(而不是库)。该属性的值是一个唯一的字符串,用于标识元素所属的格式/标准。

这些属性为唯一字符串定义了一个前缀,这样XML文档就更小、更可读。

如果要在名称空间内创建元素(或属性),则必须提供名称空间。在SimpleXMlElement中,第三个参数是命名空间。

如果没有提供名称空间,它似乎会将元素添加到父节点的名称空间中。这意味着您必须为任何没有命名空间的元素提供一个空字符串。

$root = new SimpleXMlElement('<ram:FLOW xmlns:ram="http://MY_LIBRARY" xmlns:mar="http://ANOTHER_LIBRARY"/>');
$root->addChild('header', null, '');
$data = $root->addChild('data', null, '');
$data->addChild('mar:OC_DC', null, 'http://ANOTHER_LIBRARY');
echo $root->asXml();

输出:

<?xml version="1.0"?>
<ram:FLOW xmlns:ram="http://MY_LIBRARY" xmlns:mar="http://ANOTHER_LIBRARY">
   <header xmlns=""/>
   <data xmlns="">
       <mar:OC_DC/>
   </data>
</ram:FLOW>

我还没有找到避免xmlns属性为空的方法。

DOM更显式。创建和追加逻辑是分开的。

const XMLNS_RAM = 'http://MY_LIBRARY';
const XMLNS_MAR = 'http://ANOTHER_LIBRARY';
$dom = new DOMDocument();
// appending an element with a namespace with define it if needed
$root = $dom->appendChild($dom->createElementNS(XMLNS_RAM, 'ram:FLOW'));
// setting the xmlns attribute explicit avoids the definition in descendant nodes
$root->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:mar', XMLNS_MAR);
$root->appendChild($dom->createElement('header'));
$data = $root->appendChild($dom->createElement('data'));
$data->appendChild($dom->createElementNS(XMLNS_MAR, 'mar:OC_DC'));
$dom->formatOutput = true;
echo $dom->saveXml();

输出:

<?xml version="1.0"?>
<ram:FLOW xmlns:ram="http://MY_LIBRARY" xmlns:mar="http://ANOTHER_LIBRARY">
  <header/>
  <data>
    <mar:OC_DC/>
  </data>
</ram:FLOW>