PHP için SimpleXML belirli bir niteliği, bir çocuk kaldır

13 Cevap php

Ben SimpleXML ile erişmek kulüpler farklı özelliklere sahip birkaç benzer unsurlar var:

<data>
    <seg id="A1"/>
    <seg id="A5"/>
    <seg id="A12"/>
    <seg id="A29"/>
    <seg id="A30"/>
</data>

Ben "A12" bir kimliği olan bir spesifik seg elemanı, bunu nasıl yapabilirim kaldırmak gerekir? Ben seg elemanları ve unset ting belirli bir döngü denedim, ama bu işe yaramazsa, elemanları kalır.

foreach($doc->seg as $seg)
{
    if($seg['id'] == 'A12')
    {
        unset($seg);
    }
}

13 Cevap

SimpleXML yolu [1] to remove or reorder XML nodes. Its modification capabilities are somewhat limited. You have to resort to using the DOM uzantısı içerir. dom_import_simplexml() bir DOMElement içine SimpleXMLElement dönüştürme size yardımcı olacaktır.

(PHP 5.2.5 ile test) sadece bazı örnek kod:

$data='<data>
    <seg id="A1"/>
    <seg id="A5"/>
    <seg id="A12"/>
    <seg id="A29"/>
    <seg id="A30"/>
</data>';
$doc=new SimpleXMLElement($data);
foreach($doc->seg as $seg)
{
    if($seg['id'] == 'A12') {
        $dom=dom_import_simplexml($seg);
        $dom->parentNode->removeChild($dom);
    }
}
echo $doc->asXml();

çıkışlar

<?xml version="1.0"?>
<data><seg id="A1"/><seg id="A5"/><seg id="A29"/><seg id="A30"/></data>

Arada: belirli düğümler seçerek XPath kullandığınızda çok daha basit (SimpleXMLElement->xpath):

$segs=$doc->xpath('//seq[@id="A12"]');
if (count($segs)>=1) {
    $seg=$segs[0];
}
// same deletion procedure as above

Mevcut cevapları Sanılanın aksine, her SimpleXML eleman düğümü sadece kendisi tarafından belgeden kaldırılır ve unset(). Durumda nokta SimpleXML aslında nasıl çalıştığını anlamak gerekir sadece.

İlk kaldırmak istediğiniz öğesini bulun:

list($element) = $doc->xpath('/*/seg[@id="A12"]');

Sonra $element Eğer unset temsil öğe kaldırmak onun self-reference:

unset($element[0]);

Herhangi bir öğenin ilk elemanı SimpleXML (self-başvuru) elemanının kendisi olduğu için bu çalışır. Bu sihirli doğa ile ilgisi yoktur, sayısal endeksler herhangi bir liste öğelerini (örneğin ebeveyn-> çocuklar) temsil edilir, ve hatta tek bir çocuk böyle bir liste.

Sigara sayısal dizge endeksleri (dizi-erişim) özelliklerini temsil veya çocuk-eleman (lar) (emlak-erişim).

Mülkiyet erişim nedenle sayısal indecies gibi:

unset($element->{0});

olarak iyi çalışır.

Doğal olarak bu xpath örnek ile, oldukça yalındır (PHP 5.4) 'dir:

unset($doc->xpath('/*/seg[@id="A12"]')[0][0]);

Tam bir örnek kod (Demo):

<?php
/**
 * Remove a child with a specific attribute, in SimpleXML for PHP
 * @link http://stackoverflow.com/a/16062633/367456
 */

$data=<<<DATA
<data>
    <seg id="A1"/>
    <seg id="A5"/>
    <seg id="A12"/>
    <seg id="A29"/>
    <seg id="A30"/>
</data>
DATA;


$doc = new SimpleXMLElement($data);

unset($doc->xpath('seg[@id="A12"]')[0]->{0});

$doc->asXml('php://output');

Çıktı:

<?xml version="1.0"?>
<data>
    <seg id="A1"/>
    <seg id="A5"/>

    <seg id="A29"/>
    <seg id="A30"/>
</data>

Sadece düğüm unset:

$str = <<<STR
<a>
  <b>
    <c>
    </c>
  </b>
</a>
STR;

$xml = simplexml_load_string($str);
unset($xml –> a –> b –> c); // this would remove node c
echo $xml –> asXML(); // xml document string without node c

Bu kod, How to delete / remove nodes in SimpleXML alınmıştır.

Ben Stefan'ın cevap hakkı olduğuna inanıyoruz. Eğer sadece tek bir düğüme (ziyade tüm eşleşen düğümler) kaldırmak istiyorsanız, burada başka bir örnek:

//Load XML from file (or it could come from a POST, etc.)
$xml = simplexml_load_file('fileName.xml');

//Use XPath to find target node for removal
$target = $xml->xpath("//seg[@id=$uniqueIdToDelete]");

//If target does not exist (already deleted by someone/thing else), halt
if(!$target)
return; //Returns null

//Import simpleXml reference into Dom & do removal (removal occurs in simpleXML object)
$domRef = dom_import_simplexml($target[0]); //Select position 0 in XPath array
$domRef->parentNode->removeChild($domRef);

//Format XML to save indented tree rather than one line and save
$dom = new DOMDocument('1.0');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xml->asXML());
$dom->save('fileName.xml');

Bölümleri Yük XML ... (ilk) ve Biçim XML ... (son) farklı kod, XML veri geliyor ve çıkışı ile ne yapmak istediğinize yere bağlı ile değiştirilmesi olabileceğini unutmayın; o bir düğüm bulmak ve çıkarmak arasında olduğu bölümler.

Buna ek olarak, eğer deyim hedef düğüm taşımak denemeden önce var olmasını sağlamak için sadece vardır. Bu durumda işlemek veya görmezden farklı yollar seçebilirsiniz.

Benim için bu iş:

    $data = '<data>
    <seg id="A1"/>
    <seg id="A5"/>
    <seg id="A12"/>
    <seg id="A29"/>
    <seg id="A30"/></data>';
$doc = new SimpleXMLElement($data);

$segarr = $doc->seg;

$count = count($segarr);

$j = 0;

for ($i = 0; $i < $count; $i++) {

    if ($segarr[$j]['id'] == 'A12') {
        unset($segarr[$j]);
        $j = $j - 1;
    }
    $j = $j + 1;
}

echo $doc->asXml();

Eğer baz SimpleXMLElement sınıfını genişleten, bu yöntemi kullanabilirsiniz:

class MyXML extends SimpleXMLElement {

    public function find($xpath) {
        $tmp = $this->xpath($xpath);
        return isset($tmp[0])? $tmp[0]: null;
    }

    public function remove() {
        $dom = dom_import_simplexml($this);
        return $dom->parentNode->removeChild($dom);
    }

}

// Example: removing the <bar> element with id = 1
$foo = new MyXML('<foo><bar id="1"/><bar id="2"/></foo>');
$foo->find('//bar[@id="1"]')->remove();
print $foo->asXML(); // <foo><bar id="2"/></foo>

İleride, SimpleXML ile düğümleri silmek, belgenin tam yapısını bilmiyorum, özellikle eğer, bazen bir ağrı olabilir. Ben yazdım yüzden SimpleDOM, birkaç kolaylık yöntemleri eklemek SimpleXMLElement genişleten bir sınıf.

Örneğin, deleteNodes () Bir XPath ifadesi ile eşleşen tüm düğümler silecektir. Eğer niteliği olmayan tüm düğümleri silmek istiyorsanız ve "id" "A5" eşit, yapmanız gereken tek şey:

// don't forget to include SimpleDOM.php
include 'SimpleDOM.php';

// use simpledom_load_string() instead of simplexml_load_string()
$data = simpledom_load_string(
    '<data>
        <seg id="A1"/>
        <seg id="A5"/>
        <seg id="A12"/>
        <seg id="A29"/>
        <seg id="A30"/>
    </data>'
);

// and there the magic happens
$data->deleteNodes('//seg[@id="A5"]');

yeni bir fikir:

simple_xml bir dizi olarak çalışmaktadır.

biz silmek istiyoruz "Dizi" indeksleri için arama, ve daha sonra, bu dizi dizinleri silmek için unset () işlevini kullanabilirsiniz. Benim örnek:

/ / ----------------------------

                    $pos=$this->xml->getXMLUser();
                    $i=0; $array_pos=array();
                    foreach($this->xml->doc->users->usr[$pos]->u_cfg_root->profiles->profile as $profile) {
                        if($profile->p_timestamp=='0') { $array_pos[]=$i; }
                        $i++;
                    }
                    //print_r($array_pos);
                    for($i=0;$i<count($array_pos);$i++) {
                        unset($this->xml->doc->users->usr[$pos]->u_cfg_root->profiles->profile[$array_pos[$i]]);
                    }

(Başlangıçta Perşembe günü youkey.krasnoludken.pl bana tarafından yayınlanan, 20 Ağustos, 23:13 at 2009)

Yardımcı fonksiyonlar hakkında fikir üzerinde DOM için yorumların biri olan php.net ve unset kullanma hakkında fikir kavoir.com değil. Benim için bu çözüm sonunda çalıştı:

function Myunset($node)
{
 unsetChildren($node);
 $parent = $node->parentNode;
 unset($node);
}

function unsetChildren($node)
{
 while (isset($node->firstChild))
 {
 unsetChildren($node->firstChild);
 unset($node->firstChild);
 }
}

using it: $xml is SimpleXmlElement

Myunset($xml->channel->item[$i]);

Sonuç $ xml saklanır, böylece herhangi bir değişkene atama konusunda endişelenmeyin.

SimpleXML öğeleri kaldırmak için ayrıntılı bir yol yok olsa bile, can PHP'nin unset() ile SimpleXML öğeleri kaldırın. Bunu yapmanın anahtarı istenilen elemanı hedef yönetiyor. Hedefleme yapmak için en az bir yol elemanları sırasını kullanıyor. Önce (bir döngü ile örneğin) kaldırmak istediğiniz elemanın sıra numarasını bulmak, ardından elemanı kaldırın:

$target = false;
$i = 0;
foreach ($xml->seg as $s) {
  if ($s['id']=='A12') { $target = $i; break; }
  $i++;
}
if ($target !== false) {
  unset($xml->seg[$target]);
}

Hatta bir dizi hedef öğeleri sipariş numarası depolayarak, bu birden çok öğeleri kaldırabilirsiniz. Sadece doğal bir öğeyi kaldırmak ondan sonra gelip öğelerin sırası sayısını azaltır (array_reverse($targets)), çünkü bir ters sırayla kaldırma yapmayı unutmayın.

Kuşkusuz, bu bir hackaround biraz, ama ince iş gibi görünüyor.

Sizin ilk yaklaşım haklıydı, ama foreach hakkında küçük bir şeyi unuttu. Bu özgün dizi / nesne üzerinde çalışır, ancak dolaşır gibi, her öğenin bir kopyasını oluşturur, bu nedenle kopyasını unset yaptım değildir. Bu gibi başvuru kullanın:

foreach($doc->seg as &$seg) 
{
    if($seg['id'] == 'A12')
    {
        unset($seg);
    }
}

I was also strugling with this issue and the answer is way easier than those provided over here. you can just look for it using xpath and unset it it the following method:

unset($XML->xpath("NODESNAME[@id='test']")[0]->{0});

Bu kod id niteliği "test" ile "NODESNAME" adında bir düğüm için bakmak ve ilk görüldüğü kaldıracaktır.

$ XML-> SaveXML (...) kullanarak xml kaydetmek için hatırlıyorum;

Ben Gerry gibi aynı ölümcül hatayla karşılaştı ve ben DOM aşina değilim beri, ben böyle yapmaya karar verdi:

    $item = $xml->xpath("//seg[@id='A12']");
    $page = $xml->xpath("/data");
    $id = "A12";

    if (  count($item)  &&  count($page) ) {
        $item = $item[0];
        $page = $page[0];

         // find the numerical index within ->children().
        $ch = $page->children();
        $ch_as_array = (array) $ch;

        if (  count($ch_as_array)  &&  isset($ch_as_array['seg'])  ) {
            $ch_as_array = $ch_as_array['seg'];
            $index_in_array = array_search($item, $ch_as_array);
            if (  ($index_in_array !== false)
              &&  ($index_in_array !== null)
              &&  isset($ch[$index_in_array])
              &&  ($ch[$index_in_array]['id'] == $id)  ) {

                 // delete it!
                unset($ch[$index_in_array]);

                echo "<pre>"; var_dump($xml); echo "</pre>";
            }
        }  // end of ( if xml object successfully converted to array )
    }  // end of ( valid item  AND  section )