2009-04-20 3 views
6

私は、SimpleXMLElementオブジェクト$ childとSimpleXMLElementオブジェクト$ parentを持っています。SimpleXMLでは、既存のSimpleXMLElementを子要素として追加するにはどうすればよいですか?

$ parentを$ parentの子として追加するにはどうすればよいですか? DOMに変換して戻すことなくこれを行う方法はありますか?

addChild()メソッドは新しい空の要素を作成することしかできないようですが、$ childを追加する要素にも子がある場合は役に立ちません。私はここで再帰が必要かもしれないと思っています。

答えて

6

これは最も役立つ答えではありませんが、特にXMLを作成/変更しているので、DOM機能の使用に切り替えることができます。 SimpleXMLはシンプルなドキュメントにはアクセスしやすいが、ドキュメントを変更するのには貧弱だ。

SimpleXMLがあなたを他のすべての場所で親切に扱い、それに固執したい場合は、dom_import_simplexml()を使用して、必要な機能を一時的に実行するために一時的にDOM機能にジャンプするオプションがあります。 simplexml_import_dom()。私はこれがどれほど効率的かは分かりませんが、それはあなたを助けるかもしれません。

+0

幸いにも、私はDOM(おそらく1時間かかります)にすべてのものを変換することによってあまりにも多くの時間を無駄にしないように十分早いです。他の誰かが本当にすばらしいアイデアを持っていない限り、これは私がおそらく終わらせる解決策だと思います。 答えをありがとう! – thomasrutter

+1

私は同じ問題を抱えていました。 DOMに切り替えて、それははるかに良いです。 – Keyo

0

これをここに残すと、私はこのページを見つけただけで、SimpleXMLは::addChild methodでこの機能をサポートするようになりました。

あなたにも任意のカスケード要素を追加行うには、このメソッドを使用することができます:あなたはaddChild()が定義されているどのように注意深く見る場合

$xml->addChild('parent'); 
$xml->parent->addChild('child'); 
$xml->parent->child->addChild('child_id','12345'); 
+0

これは疑問が**既にSimpleXMLElementノード**である子を追加していたので質問に答えません。 – richard

1

実際に、それは(動的)が可能です。私は、再帰を使用して、XMLに任意の配列を変換し、参照渡し

  • addChild()戻り添加子のSimpleXMLElementをするためにこの技術を使用します。
  • リーフノードを追加するには、$xml->addChilde($nodeName, $nodeValue)を使用します。
  • サブノードまたは値を持つノードを追加するには、 $xml->addChilde($nodeName)を使用し、addChild()に値は渡されません。この は、タイプSimpleXMLElementのサブノードを持つことになります。ない 文字列!

ターゲットXML

<root> 
    <node>xyz</node> 
    <node> 
     <node>aaa</node> 
     <node>bbb</node> 
    </node> 
</root> 

コード:

$root = new SimpleXMLElement('<root />'); 
//add child with name and string value. 
$root.addChild('node', 'xyz'); 
//adds child with name as root of new SimpleXMLElement 
$sub = $root->addChild('node'); 
$sub.addChild('node', 'aaa'); 
$sub.addChild('node', 'bbb'); 
+0

これは質問に答えません。問題は、すでにSimpleXMLElement **である子を追加する方法でした**。 – richard

7

残念ながらSimpleXMLElementは、2つの要素を一緒に持って来るために何を提供していません。 @nickf wroteのように、それは操作よりも読みに適しています。ただし、姉妹の内線番号DOMDocumentは編集用です。dom_import_simplexml()で両方を一緒に持ち込むことができます。 @salathe shows in a related answerこれは特定のSimpleXMLElementsでどのように動作するのですか?

入力チェックといくつかのオプションでこれがどのように機能するかを以下に示します。私は2つの例でそれを行います。

/** 
* Insert XML into a SimpleXMLElement 
* 
* @param SimpleXMLElement $parent 
* @param string $xml 
* @param bool $before 
* @return bool XML string added 
*/ 
function simplexml_import_xml(SimpleXMLElement $parent, $xml, $before = false) 
{ 
    $xml = (string)$xml; 

    // check if there is something to add 
    if ($nodata = !strlen($xml) or $parent[0] == NULL) { 
     return $nodata; 
    } 

    // add the XML 
    $node  = dom_import_simplexml($parent); 
    $fragment = $node->ownerDocument->createDocumentFragment(); 
    $fragment->appendXML($xml); 

    if ($before) { 
     return (bool)$node->parentNode->insertBefore($fragment, $node); 
    } 

    return (bool)$node->appendChild($fragment); 
} 

この例示的な機能は、XMLを追加またはルート要素を含む、特定の要素の前に挿入することを可能にする:最初の例では、XML文字列を挿入する機能です。追加するものがあるかどうかを確認した後、DOMDocumentの機能を使用して、XMLをドキュメントフラグメントとして挿入します。How to import XML string in a PHP DOMDocumentにも概要が示されています。これは次のような出力が得られる

$parent = new SimpleXMLElement('<parent/>'); 

// insert some XML 
simplexml_import_xml($parent, "\n <test><this>now</this></test>\n"); 

// insert some XML before a certain element, here the first <test> element 
// that was just added 
simplexml_import_xml($parent->test, "<!-- leave a comment -->\n ", $before = true); 

// you can place comments above the root element 
simplexml_import_xml($parent, "<!-- this works, too -->", $before = true); 

// but take care, you can produce invalid XML, too: 
// simplexml_add_xml($parent, "<warn><but>take care!</but> you can produce invalid XML, too</warn>", $before = true); 

echo $parent->asXML(); 

:使用例

<?xml version="1.0"?> 
<!-- this works, too --> 
<parent> 
    <!-- leave a comment --> 
    <test><this>now</this></test> 
</parent> 

を第二の例では、SimpleXMLElement挿入されます。必要に応じて、最初の関数を使用します。基本的には、何かするべきことがあり、どの種類の要素がインポートされるかをチェックします。

/** 
* Insert SimpleXMLElement into SimpleXMLElement 
* 
* @param SimpleXMLElement $parent 
* @param SimpleXMLElement $child 
* @param bool $before 
* @return bool SimpleXMLElement added 
*/ 
function simplexml_import_simplexml(SimpleXMLElement $parent, SimpleXMLElement $child, $before = false) 
{ 
    // check if there is something to add 
    if ($child[0] == NULL) { 
     return true; 
    } 

    // if it is a list of SimpleXMLElements default to the first one 
    $child = $child[0]; 

    // insert attribute 
    if ($child->xpath('.') != array($child)) { 
     $parent[$child->getName()] = (string)$child; 
     return true; 
    } 

    $xml = $child->asXML(); 

    // remove the XML declaration on document elements 
    if ($child->xpath('/*') == array($child)) { 
     $pos = strpos($xml, "\n"); 
     $xml = substr($xml, $pos + 1); 
    } 

    return simplexml_import_xml($parent, $xml, $before); 
} 

この典型的な機能は、要素のリストを正規化して行います。それは属性である場合、それはちょうどそれが要素である場合、それはXMLにシリアライズして、XMLとしての親要素に追加され、それを追加しますSimplexmlに共通する属性一度に複数のSimpleXMLElementsを挿入するためにそれを変更したい場合がありますが、使用例は、以下に示すように、私の例は、(属性の例を参照)ことをサポートしていません。

// append the element itself to itself 
simplexml_import_simplexml($parent, $parent); 

// insert <this> before the first child element (<test>) 
simplexml_import_simplexml($parent->children(), $parent->test->this, true); 

// add an attribute to the document element 
$test = new SimpleXMLElement('<test attribute="value" />'); 
simplexml_import_simplexml($parent, $test->attributes()); 

echo $parent->asXML(); 

これは最初のusage-の続きです例。したがって出力は次のようになります。

<?xml version="1.0"?> 
<!-- this works, too --> 
<parent attribute="value"> 
    <!-- leave a comment --> 
    <this>now</this><test><this>now</this></test> 
<!-- this works, too --> 
<parent> 
    <!-- leave a comment --> 
    <test><this>now</this></test> 
</parent> 
</parent> 

これは役に立ちます。 find the code in a gistonline demo/PHP version overviewとすることができます。

関連する問題