0

What is the best way to delete everything between an opening tag and a closing tag with php in an XML file?

I have a XML file like this

    <CATALOG id="1">
       <CD>
          <TITLE>Empire Burlesque</TITLE>
          <ARTIST>Bob Dylan</ARTIST>
          <COUNTRY>USA</COUNTRY>
          <COMPANY>Columbia</COMPANY>
          <PRICE>10.90</PRICE>
          <YEAR>1985</YEAR>
       </CD>
    </CATALOG>
    <CATALOG id="2">
       <CD>
          <TITLE>Empire Burlesque</TITLE>
          <ARTIST>Bob Dylan</ARTIST>
          <COUNTRY>USA</COUNTRY>
          <COMPANY>Columbia</COMPANY>
          <PRICE>10.90</PRICE>
          <YEAR>1985</YEAR>
       </CD>
    </CATALOG>
    <CATALOG id="3">
       <CD>
          <TITLE>Empire Burlesque</TITLE>
          <ARTIST>Bob Dylan</ARTIST>
          <COUNTRY>USA</COUNTRY>
          <COMPANY>Columbia</COMPANY>
          <PRICE>10.90</PRICE>
          <YEAR>1985</YEAR>
       </CD>
    </CATALOG>

And for example I want to delete everything between the first <CATALOG id="1"></CATALOG>

Any suggestions?

GCallie
  • 413
  • 1
  • 3
  • 11
  • 2
    Load the XML into a DOM, loop through the DOM, remove nodes that have that id or other undesired attribute, save the result back to XML. http://php.net/manual/en/refs.xml.php – deceze Jul 17 '14 at 09:45
  • @deceze I was also thinking that way, but in jquery I also read the same XML file for other purposes but there you can find your tag you're looking for, as soon it find that tag you can handle everything between the opening tag and the closing tag. $(xml).find('CATALOG').each(function(){ if($(this).attr('ID') == '1') { ... But how should I do that with PHP when I load XML into a DOM – GCallie Jul 17 '14 at 10:05

4 Answers4

1

something like this

//edit

please note that this solution removes the element, if only the content should be cleared then use the solution from jazZRo.

$xml = '<data><CATALOG id="1">
       <CD>
          <TITLE>Empire Burlesque</TITLE>
          <ARTIST>Bob Dylan</ARTIST>
          <COUNTRY>USA</COUNTRY>
          <COMPANY>Columbia</COMPANY>
          <PRICE>10.90</PRICE>
          <YEAR>1985</YEAR>
       </CD>
    </CATALOG>
    <CATALOG id="2">
       <CD>
          <TITLE>Empire Burlesque</TITLE>
          <ARTIST>Bob Dylan</ARTIST>
          <COUNTRY>USA</COUNTRY>
          <COMPANY>Columbia</COMPANY>
          <PRICE>10.90</PRICE>
          <YEAR>1985</YEAR>
       </CD>
    </CATALOG>
    <CATALOG id="3">
       <CD>
          <TITLE>Empire Burlesque</TITLE>
          <ARTIST>Bob Dylan</ARTIST>
          <COUNTRY>USA</COUNTRY>
          <COMPANY>Columbia</COMPANY>
          <PRICE>10.90</PRICE>
          <YEAR>1985</YEAR>
       </CD>
    </CATALOG></data>';

$doc = new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
foreach($xpath->query("//CATALOG[@id=3]") as $node )
{
    $node->parentNode->removeChild($node);
}

echo $doc->saveXML();
ins0
  • 3,918
  • 1
  • 20
  • 28
  • This removes the CATALOG tag, the OP wants to empty it, not remove it. – jazZRo Jul 17 '14 at 11:12
  • i updated my answer, thanks - don't think it is necessary that i implement the other function in my answer, i would do exactly the same like you wrote jazZRo. – ins0 Jul 17 '14 at 11:29
1

DOMNode::nodeValue is a writeable property. I would not use it to set values because of the broken entity handling, but an empty string contains no entities.

$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
foreach($xpath->evaluate("//CATALOG[@id=3]") as $node) {
  $node->nodeValue = '';
}

echo $doc->saveXML();
ThW
  • 19,120
  • 3
  • 22
  • 44
0

It can be done using DOMDocument and DOMXPath. For example:

$dom = new DOMDocument();
$dom->loadXML($xml); // loads XML from a string, use $dom->load() to load from a file
$xpath = new DOMXPath($dom);
$cat = $xpath->query('//CATALOG[@id="1"]')->item(0);
while($cat->firstChild) {
    $cat->removeChild($cat->firstChild);    
}
jazZRo
  • 1,598
  • 1
  • 14
  • 18
-1

You can use the following solution using the DOMDocument class:

//the xml content.
$xml = '
    <CATALOGS>
      <CATALOG id="1">
        <CD>
          <TITLE>Empire Burlesque</TITLE>
          <ARTIST>Bob Dylan</ARTIST>
          <COUNTRY>USA</COUNTRY>
          <COMPANY>Columbia</COMPANY>
          <PRICE>10.90</PRICE>
          <YEAR>1985</YEAR>
        </CD>
      </CATALOG>
      <CATALOG id="2">
        <CD>
          <TITLE>Empire Burlesque</TITLE>
          <ARTIST>Bob Dylan</ARTIST>
          <COUNTRY>USA</COUNTRY>
          <COMPANY>Columbia</COMPANY>
          <PRICE>10.90</PRICE>
          <YEAR>1985</YEAR>
        </CD>
      </CATALOG>
      <CATALOG id="3">
        <CD>
          <TITLE>Empire Burlesque</TITLE>
          <ARTIST>Bob Dylan</ARTIST>
          <COUNTRY>USA</COUNTRY>
          <COMPANY>Columbia</COMPANY>
          <PRICE>10.90</PRICE>
          <YEAR>1985</YEAR>
        </CD>
      </CATALOG>
    </CATALOGS>';

//load the XML string as DOM document.
$domDoc = new DOMDocument();
$domDoc->loadXML($xml);

//create XPath object to navigate through the XML content.
$xpath = new DOMXPath($domDoc);

//find all elements "CATALOG" with the attribute "id" with value "1" 
//and run through the found elements.
foreach ($xpath->query("//CATALOG[@id=1]") as $domNode) {
    $domNode->nodeValue = '';
}

$xml = $domDoc->saveXML();

Note: Your XML string is not well formed. The root element of the XML is missing. To provide a working solution I added the <CATALOGS> root element.

Sebastian Brosch
  • 42,106
  • 15
  • 72
  • 87
  • `` - ooops. Or: `...` - oooops. – deceze Jul 17 '14 at 10:07
  • 3
    can't recommend this solution – ins0 Jul 17 '14 at 10:51
  • 1
    because you skip all validations that after the replacement the xml is still valid. so you don't exactly know if a error is thrown, the preg_replace will replace without mercy. with native php functions a error is thrown that can be catched. – ins0 Jul 17 '14 at 11:07
  • 2
    Don't use regex for XML, [this is why](http://stackoverflow.com/questions/6751105/why-its-not-possible-to-use-regex-to-parse-html-xml-a-formal-explanation-in-la). – jazZRo Jul 17 '14 at 11:21