【问题标题】:SimpleXML - add a new node using a namespace previously declared - how?SimpleXML - 使用先前声明的命名空间添加新节点 - 如何?
【发布时间】:2011-03-27 05:13:18
【问题描述】:

我想为<domain:create> 节点添加一个子节点,在一个非常具体的地方(所以我也使用 DOM 而不仅仅是 simpleXML)。

我尝试在 simpleXML 构造中使用 $ns 属性。

$nsNode = new SimpleXMLElement('<domain:ns>', $options = 0, $ns='urn:ietf:params:xml:ns:domain-1.0');

//transform the target into dom object for manipulation
$nodeRegistrantDom = dom_import_simplexml($nodeRegistrant);

但我得到了:

I/O 警告:无法加载外部 实体"&lt;domain:ns&gt;"

我尝试在创建元素后注册前缀, 但是之后我没有使用 xpath,所以这是一个非常没用的尝试......

//creates the simpleXML object node to be inserted.
$nsNode = new SimpleXMLElement('<ns/>');

//this will not work, because we will not use xpath after it :s
$nsNode->registerXPathNamespace('domain', 'urn:ietf:params:xml:ns:domain-1.0');

既然 xml 是从一个文件中加载的,并且这个 ns 声明的那个文件,也许我们应该从那个文件中获取它?

这里是上面的一个整体,以便我们更好地理解上下文: 我们正在加载一个包含整体结构的 XML 文件:

 $xmlObj = simplexml_load_file('EppCreateDomain.xml');

我们将抓取一个我们将用作目标的元素:

//grab the target.
    $nodeRegistrant = $xmlObj->command->create->children(self::OBJ_URI_DOMAIN)->create->registrant;

    //transform the target into a dom object for later manipulation
    $nodeRegistrantDom = dom_import_simplexml($nodeRegistrant);

//we try to use simpleXML to create the node that we want to add after our target.
    $nsNode = new SimpleXMLElement('<domain:ns>');


//grabs the node and all his children (none in this case), by importing the node we want to add,
//into the root object element that contains the <domain:registrant> node.
$nsNodeDom = $nodeRegistrantDom->ownerDocument->importNode(dom_import_simplexml($nsNode), true);

$nodeRegistrantDom->parentNode->insertBefore($nsNodeDom, $nodeRegistrantDom->nextSibling);

$simpleXmlNsNode = simplexml_import_dom($nsNodeDom);

现在我们将节点放置在适当的位置。 并转换为 simpleXML,我们现在可以轻松添加一些子项并填充 xml 文件的其余部分..

$hostAttr = $simpleXmlNsNode->addChild('domain:hostAttr');
$hostName = $hostAttr->addChild('domain:hostName');

请指教, 内存

【问题讨论】:

  • 你能发布一个小例子来说明你的问题吗?至少我对发生的事情和原因感到有些困惑。例如。 $nodeRegistrant?这是哪里来的?
  • 当然。马上。很难把它的一部分剪下来作为一个问题。我将添加更多信息。 5 分钟。

标签: php namespaces simplexml


【解决方案1】:

既然 xml 是从一个文件中加载的,并且这个 ns 声明的那个文件,也许我们应该从那个文件中获取它?

如果该文件是 XML 文件,是的,您应该加载整个文件,而不仅仅是一部分。

一旦命名空间被声明,添加命名空间元素就很容易了:

<?php
$xml = <<<XML
<epp>
    <domain:create xmlns:domain="urn:someurn" xmlns:ietf="urn:thaturn">
       <domain:name></domain:name>
       <domain:registrant></domain:registrant>
       <domain:contact></domain:contact>
    </domain:create>
</epp>
XML;

$sxml = new SimpleXMLElement($xml);
$sxml->children("domain", true)->create->addChild("newElem", "value", "urn:thaturn");
echo $sxml->saveXML();

给予

<?xml version="1.0"?>
<epp>
    <domain:create xmlns:domain="urn:someurn" xmlns:ietf="urn:thaturn">
       <domain:name/>
       <domain:registrant/>
       <domain:contact/>
    <ietf:newElem>value</ietf:newElem></domain:create>
</epp>

【讨论】:

  • 是的。我正在从文件中加载 XML。使用 addChild 是一个不错的功能,但是,我不能在这种情况下使用它,因为它会将我们添加的节点 放在所有兄弟节点的末尾,但是,这个节点需要放在 节点。任何其他方式来存档它,但不依赖“addChild”? K. 问候,MEM
  • @MEM 看到这个问题:stackoverflow.com/questions/3432358/… 你只需要使用 DOMDocument::createElementNS 而不是 DOMDocument::createElement
  • @Artefacto:我预计这甚至是同一个用户的问题;-) 无论如何,这是一个 bit 不同的问题。在这种情况下,它不是位置索引,而是needs to be placed after &lt;domain:registrant/&gt; node。 @MEM:问题是:是否总是存在 domain:registrant 元素?如果没有,是否有备用规则?
  • 我可以成功地在 之后放置一个节点,但是我可以这样做,没有命名空间。是的。 将始终存在。非常感谢。
  • @MEM 好吧,这是一个微不足道的修改。确定该元素在$chnodes 数组中的位置,而不是传递索引。
【解决方案2】:
<?php
// test document, registrant as first/last element and somewhere in between
$xmlObj = new SimpleXMLElement('<epp>
  <domain:create xmlns:domain="urn:someurn">
    <domain:name></domain:name>
    <domain:registrant></domain:registrant>
    <domain:contact></domain:contact>
  </domain:create>
  <domain:create xmlns:domain="urn:someurn">
    <domain:name></domain:name>
    <domain:contact></domain:contact>
    <domain:registrant></domain:registrant>
  </domain:create>
  <domain:create xmlns:domain="urn:someurn">
    <domain:registrant></domain:registrant>
    <domain:name></domain:name>
    <domain:contact></domain:contact>
  </domain:create>
</epp>');

foreach( $xmlObj->children("urn:someurn")->create as $create ) {
  $registrant = $create->registrant;
  insertAfter($registrant, 'domain:ns', 'some text');
}
echo $xmlObj->asXML();

function insertAfter(SimpleXMLElement $prevSibling, $qname, $val) {
  $sd = dom_import_simplexml($prevSibling);
  $newNode = $sd->ownerDocument->createElement($qname, $val);
  $newNode = $sd->parentNode->insertBefore($newNode, $sd->nextSibling);
  return simplexml_import_dom($newNode);
}

打印

<?xml version="1.0"?>
<epp>
  <domain:create xmlns:domain="urn:someurn">
    <domain:name/>
    <domain:registrant/><domain:ns>some text</domain:ns>
    <domain:contact/>
  </domain:create>
  <domain:create xmlns:domain="urn:someurn">
    <domain:name/>
    <domain:contact/>
    <domain:registrant/><domain:ns>some text</domain:ns>
  </domain:create>
  <domain:create xmlns:domain="urn:someurn">
    <domain:registrant/><domain:ns>some text</domain:ns>
    <domain:name/>
    <domain:contact/>
  </domain:create>
</epp>

【讨论】:

  • 我正在研究它... :) 我需要几个小时。是的,我就是那个傻瓜。
  • 你好,请问各位能不能回复一下这个问题: 1)你们的两个答案,都是函数的形式。为什么?是的,这是一个非常基本的问题,但我也是一个非常基本的编码员,因为我对此没有超过 1 年的经验。 :s 再次感谢,MEM
  • 疑点二:为什么要 createElement('domain:ns');工作,这个 importNode(dom_import_simplexml($nsNode), true);不是吗?
  • 疑点三:当我们使用createElement的时候,是不是意味着它会被创建,但是放在任何地方?那是因为我们可以使用 insertBefore 来正确放置它?
  • 疑问 4:如果我们需要向元素添加一些子元素,并且这些子元素也需要命名空间前缀,我们必须: $hostAttr = $simpleXmlNsNode->addChild('domain:hostAttr' , null, self::OBJ_URI_DOMAIN);为什么我们需要重新声明我们的命名空间。当我们返回 simplexml_import_dom($newNode); 时不应该在那里?
猜你喜欢
  • 2018-02-11
  • 2012-07-05
  • 2011-04-28
  • 1970-01-01
  • 2012-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-21
相关资源
最近更新 更多