title: Using XML::LibXML to find and replace specific portions of a CableLabs 1.0 XML file
body: <p>I have tried <code>XML Simple</code>, but due to the fact that it just reads the XML into a hash, the output is useless when run against the DTD. Learned it the hard way.</p>
  
  <p>So I have adopted <code>XML::LibXML</code>, the funny thing is the requirements that I found most difficult to accomplish with <code>XML::Simple</code>, were the easiest. However I am finding that some of easier things to do in <code>XML::Simple</code> are proving to be impossible (with my lack of understanding of DOM, and some confusing behaviors with <code>XML::LibXML</code>).</p>
  
  <p>So here is a sample of the XML:</p>
  
  <pre><code>    &lt;Metadata&gt;
          &lt;ADI Name="movie" /&gt;
          &lt;App_Data Name="Something I don't care about" value="who cares" /&gt;
          &lt;App_Data Name="Something I don't care about as well" value="who cares" /&gt;
          &lt;App_Data Name="ChangeMe" Value="" /&gt;
      &lt;/Metadata&gt;
      &lt;Metadata&gt;
          &lt;ADI Name="photo" /&gt;
          &lt;App_Data Name="Something I don't care about" value="who cares" /&gt;
          &lt;App_Data Name="Something I don't care about as well" value="who cares" /&gt;
          &lt;App_Data Name="ChangeMe" Value="" /&gt;
      &lt;/Metadata&gt;
      &lt;Metadata&gt;
          &lt;ADI Name="poster" /&gt;
          &lt;App_Data Name="Something I don't care about" value="who cares" /&gt;
          &lt;App_Data Name="Something I don't care about as well" value="who cares" /&gt;
          &lt;App_Data Name="ChangeMe" Value="" /&gt;
      &lt;/Metadata&gt;
  </code></pre>
  
  <p>Note: I have simplified this for the use in this post.  </p>
  
  <p>So basically I have to use the <code>Name</code> field in the <code>&lt;ADI&gt;</code> tag to confirm that I am in the correct area of the DOM to make the change to the <code>Value</code> attribute in the <code>&lt;App_Data&gt;</code> tag that who's <code>Name</code> is <code>ChangeMe</code>.</p>
  
  <p>This is the snippet of code that I have come up with... and failed miserably.</p>
  
  <pre><code>#!/usr/bin/perl
  
  use strict;
  use XML::LibXML;
  
  my $xml2 = XML::LibXML-&gt;new();
  my $data = $xml2-&gt;parse_file("adi.xml");
  my $movie;
  my $photo;
  my $poster;
  
  foreach my $test ($data-&gt;findnodes('//Metadata')) {
      if ($test-&gt;findvalues('./ADI/@Name[.="movie"]')){
          $movie = 1;
          undef $photo;
          undef $poster;
      }
      elsif ($test-&gt;findvalues('./ADI/@Name[.="photo"]')){
          undef $movie;
          $photo = 1;
          undef $poster;
      }
      elsif ($test-&gt;findvalues('./ADI/@Name[.="poster"]')){
          undef $movie;
          undef $photo;
          $poster = 1;
      }
  }
  </code></pre>
  
  <p>I don't have anything beyond this, because it doesn't work. I get an error something along the lines of </p>
  
  <pre class="lang-none prettyprint-override"><code>Can't locate object method "findvalues" via package "XML::LibXML::Element"
  </code></pre>
  
  <p>As a bonus to this question, what if I wanted to completely remove the <code>&lt;Metadata&gt;</code> (and all children) for the ones that contained photo and/or poster?</p>