Search code examples
perlxml-libxml

Perl LIBXML : Using findnodes with attributes to reach a node in the xml file


The XML file looks like below:

<?xml version="1.0"?>
<application name="pos">
<artifact id="123" type="war" cycle="Release7-Sprint1">
<jira/>
<jenkins/>
<deployment/>
<scm>
  <transaction id="1234" user="">
    <file name=""/>
    <file name=""/>
  </transaction>
</scm>
</artifact>
</application>

My piece of code looks below and works fine when I use the hard coded value of attribute(name), instead of using a variable. I am referencing the line ( my $query =
'//application[@name="pos"]'; )

my $manifestDoc = $manifestFileParser->parse_file($manifestFile);
my $changeLogDoc = $changeLogParser->parse_file($changeLogXml );
my $changeLogRoot = $changeLogDoc->getDocumentElement;

#my $applicationName = pos;
my $query  = '//application[@name="pos"]';
my $applicationNode = $manifestDoc->findnodes($query);

my $artifactNode = $manifestDoc->createElement('artifact');
$artifactNode->setAttribute("id",$artifactID);
$artifactNode->setAttribute("type",$artifactType);
$artifactNode->setAttribute("cycle",$releaseCycle);
$applicationNode->[0]->appendChild($artifactNode);

But if I modify the $query variable to use a variable ($applicationName) instead of a hard coded value of attribute, it gives me a compilation error saying below:

Can't call method "appendChild" on an undefined value at updateManifest.pl line

Modified code:

 my $applicationName = "pos" ;
 my $query  = '//application[@name="$applicationName"]';

Not sure what is wrong. Anything to do with quotes? Any help is much appreciated.


Solution

  • The expression '//application[@name="$applicationName"]' means the literal string with those contents – no variables are interpolated with single quotes. If you'd use double quotes, then both @name and $applicationName would be interpolated.

    You have three options:

    1. Use double quotes, but escape the @:

      qq(//application[\@name="$applicationName"])
      

      The qq operator is equivalent to double quotes "…" but can have arbitrary delimiters, which avoids the need to escape the " inside the string.

    2. Concatenate the string:

      '//application[@name="' . $applicationName . '"]'
      

      This often has a tendency to be hard to read. I'd avoid this solution.

    3. Use a sprintf pattern to build the string from a template:

      sprintf '//application[@name="%s"]', $applicationName
      

      If you don't already know printf patterns, you can find them documented in perldoc -f sprintf.