(PHP) 使用命名空间前缀附加新的 XML 子元素
Posted
技术标签:
【中文标题】(PHP) 使用命名空间前缀附加新的 XML 子元素【英文标题】:(PHP) Append new XML child element(s) with namespace prefix 【发布时间】:2014-12-10 13:51:43 【问题描述】:我有一个包含多个 t:subscription
子元素的 t:subscriptions
元素的 XML。
我的主要目标是将当前的t:subsciptions
整体或所有t:subsciption
元素替换为新元素。目前我已经创建了新的t:subscription
元素作为字符串(没有掌握 dom/simplexml 类,所以我不得不使用“后备”方法)。
现在我正在尝试通过 simplexml_load_string 然后 dom_import_simplexml 将字符串转换为 XML,以便在 XML 中附加/替换当前订阅。我尝试了以下从该站点找到的示例:
$newsubs = ''; //new XML as string
$sdom = new DOMDocument();
$sdom->loadXML($xml->asXML()); // current XML
//dpm($sdom->saveXML());
$xpath = new DOMXPath($sdom);
// ... x functions generate $newsubs string ...
$remove = $sdom->getElementsByTagName('subscriptions')->item(0); // get t:subscriptions for removal
$remove->parentNode->removeChild($remove); // remove t:subscriptions
$fragment = $sdom->createDocumentFragment();
$fragment->appendXml($newsubs);
$xpaths
->evaluate('//t:member') // this node holds t:subscriptions among others
->item(0) // there's always only one member node
->appendChild($fragment);
debug($sdom->saveXML());
到目前为止,我收到的唯一错误是Namespace prefix X on Y is not defined
,这适用于所有元素。脚本会删除命名空间前缀,尽管它们是在 xml 字符串中定义的,例如 <t:myelement>asdasd</t:myelement>
。
要添加此 XML 的 XML 文档已添加前缀。我不明白为什么它不能接受带前缀的 XML 并去掉前缀,而新的 XML 却被附加到文档中?没有意义。
【问题讨论】:
【参考方案1】:错误消息可能意味着 XML 中缺少命名空间的“xmlns:*”属性,或者命名空间前缀未在 XPath 对象上注册。
XML 文档
命名空间需要在两边都定义。首先是 XML 本身。
<foo xmlns="urn:foo"/>
或
<f:foo xmlns:f="urn:foo"/>
都被解析器解析为相同的命名空间和本地名称。您可以将元素名称读取为urn:foo:foo
。
以下是 DOM 上的几个 *NS 方法,它们允许您使用命名空间。命名空间始终是 URN。前缀与匹配无关。
$node->getElementsByTagNameNS('urn:foo', 'foo')
仅在需要作为值时才提供前缀。例如创建一个使用它的元素节点。
$document->createElementNS('urn:foo', 'foo'); // no prefix
$document->createElementNS('urn:foo', 'f:foo'); // with prefix "f"
XPath
XPath 也在表达式中使用前缀。但它不应该从文档中读取它们。使用DOMXpath::registerNamespace()
为特定命名空间注册自己的前缀。
示例
您的问题缺少完整的 XML,因此我将添加一个小型 Atom 示例。可以看到命名空间在XML和php中是一样的,只是前缀不同:
$xml = <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<atom:feed xmlns:atom="http://www.w3.org/2005/Atom">
<atom:title>Example Feed</atom:title>
<atom:entry>
<atom:title>Atom-Powered Robots Run Amok</atom:title>
<atom:id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</atom:id>
</atom:entry>
</atom:feed>
XML;
$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace('a', 'http://www.w3.org/2005/Atom');
var_dump($xpath->evaluate('string(//a:entry/a:title)'));
输出:
string(28) "Atom-Powered Robots Run Amok"
【讨论】:
我只是想出了同样的事情,并将 xmlns 属性添加到新的 XML 中,它成功了!但是,尽管如此,您的回答是有根据且非常深刻的,所以非常感谢您! ...错误消息可能具有相同的直接消息“XML 中缺少名称空间的“xmlns:*”属性,而不是“嘿,您的 xml 中有一些错误,但我不会告诉它可能是什么(提示:ns)。祝你好运,如果您需要任何进一步的帮助,请访问 ***。”以上是关于(PHP) 使用命名空间前缀附加新的 XML 子元素的主要内容,如果未能解决你的问题,请参考以下文章
Jackson XML - 使用命名空间前缀反序列化 XML
XML 和 XSL 中的前缀命名空间处理由 XML 解析器返回错误
使用 Microsoft.xmldom 更改 XML 元素的命名空间前缀,以便利用 GetElementsByTagName