?
Solved

XML::XPath how to setNodeText to a chunk of XML?

Posted on 2010-04-06
4
Medium Priority
?
534 Views
Last Modified: 2013-11-11
Another XML::XPath question...

Not sure how to best ask this, but it seems when I use setNodeText = a chunk of XML, the '<' get translated to '&lt;'

So, I have  a variable called $notificationXML with the following XML as the template I am working with:

<?xml version="1.0" encoding="UTF-8"?>
<myCompanyDocument>
        <corporateHeader>
                <companyName>My Company, Inc.</companyName>
        </corporateHeader>
        <document>
                <documentHeader>
                        <documentTyp>NotificationRequest</documentTyp>
                        <documentTitle>EnterpriseCollaborator_NotificationRequest</documentTitle>
                        <documentDate>2010-03-25</documentDate>
                        <documentDesc>A request of Enterprise Notification to notify</documentDesc>
                </documentHeader>
                <notificationRequest>
                        <notificationRequestHdr>
                                <originationDateTime/>
                                <isRegistered/>
                                <notificationRgstdDesc/>
                                <requestOriginator/>
                                <recipientList/>
                        </notificationRequestHdr>
                        <notificationRequestBody>
                                <notificationRequestDtlList/>
                        </notificationRequestBody>
                </notificationRequest>
        </document>
</myCompanyDocument>



I have another "chunk" of xml in a separate variable  called $notificationDetailList that looks like the following:

<notificationRequestDtl>
        <notificationRequestDtlHdr>
                <priority>HIGH</priority>
                <severity>LOW</severity>
                <reference />
        </notificationRequestDtlHdr>
        <notificationRequestDtlBody>
        <requestDetail><realm>TEST</realm><status>Succeeded</status><user>spbmb</user><date>2010-04-02</date><time>01:01:01</time><asset>LoginEAR.ear</asset><cell>Infra</cell><cluster>Login_TESTA</cluster><failingScript>N/A</failingScript><failureMessage>N/A</failureMessage></requestDetail></notificationRequestDtlBody>
</notificationRequestDtl>


I'm using Xpath to set the notificationRequestDtlList node of $template to the value in $notificationRequest.

The substitution works fine, except all the <  that were in $notificationRequest now show up as &lt; in the updated $template variable.


Is it possible to set the node text like this with XML::XPath?  If so, can someone tell me how to keep the < from being translated to &lt;

0
Comment
Question by:Bbouch
  • 2
4 Comments
 
LVL 27

Expert Comment

by:wilcoxon
ID: 29916267
Looking over the docs for XML::XPath, I don't think that will work.  setNodeText expects the value to be text so it is escaping it.  I think you will have to set each node individually.

In other words, you'll need to set:
notificationRequestDtl/notificationRequestDtlHeader/priority = HIGH
notificationRequestDtl/notificationRequestDtlHeader/severity = LOW
etc
0
 
LVL 1

Author Comment

by:Bbouch
ID: 29929233
Ok I figured out what's happening. My lack of XML knowledge is catching up to me...

I am setting the TEXT of the notificationRequestDtlList node to some XML.  so, XPath is smart enough to know that the text happens to look like XML, and puts in the entity references in order to maintain the structure (i.e. the text of the node stays as just that and isn't translated into multiple child nodes.

Unfortunately, what I really want is multiple child nodes.  I can set the values as you suggested, but that only works if there is 1 child in the list.  In a more advanced use cases, I want multiple NotificationRequest nodes under the NotificationRequestList node.

XML::XPath doesn't seem to work in that scenario since it just overwrites the first occurrence with the second, then the third, etc...

It looks like I'm going to need a different module for what I am trying to do :(

 
0
 
LVL 27

Expert Comment

by:wilcoxon
ID: 29936567
Looking at XML::XPath documentation, it looks like it should be possible (probably involving createNode and the XML::XPath::Node sub-classes) but I can't figure it out.

For a simple solution, look at XML::Simple.  The below code pretty much does what you want but you'll have to play with the options for XMLin and XMLout to maintain the exact structure you had to start (rather than equivalent using attributes as well as elements).
#!/usr/local/bin/perl

use strict;
use warnings;
use XML::Simple;

my $xml = join '', <DATA>;

my $xp = XMLin($xml);

$xp->{document}{notificationRequest}{notificationRequestBody}{notificationRequestDtlList}{notificationRequestDtl} = [
        {       priority => 'HIGH',
                severity => 'LOW',
                reference => undef
        },
        {       priority => 'MEDIUM',
                severity => 'LOW',
                reference => undef,
        }
];

print XMLout($xp), "\n";

__DATA__
<?xml version="1.0" encoding="UTF-8"?>
<myCompanyDocument>
        <corporateHeader>
                <companyName>My Company, Inc.</companyName>
        </corporateHeader>
        <document>
                <documentHeader>
                        <documentTyp>NotificationRequest</documentTyp>
                        <documentTitle>EnterpriseCollaborator_NotificationReques
t</documentTitle>
                        <documentDate>2010-03-25</documentDate>
                        <documentDesc>A request of Enterprise Notification to no
tify</documentDesc>
                </documentHeader>
                <notificationRequest>
                        <notificationRequestHdr>
                                <originationDateTime/>
                                <isRegistered/>
                                <notificationRgstdDesc/>
                                <requestOriginator/>
                                <recipientList/>
                        </notificationRequestHdr>
                        <notificationRequestBody>
                                <notificationRequestDtlList/>
                        </notificationRequestBody>
                </notificationRequest>
        </document>
</myCompanyDocument>

Open in new window

0
 
LVL 25

Accepted Solution

by:
clockwatcher earned 2000 total points
ID: 29976410
Give the following a try.
use XML::XPath;

my $xml = q(<?xml version="1.0" encoding="UTF-8"?>
<myCompanyDocument>
        <corporateHeader>
                <companyName>My Company, Inc.</companyName>
        </corporateHeader>
        <document>
                <documentHeader>
                        <documentTyp>NotificationRequest</documentTyp>
                        <documentTitle>EnterpriseCollaborator_NotificationRequest</documentTitle>
                        <documentDate>2010-03-25</documentDate>
                        <documentDesc>A request of Enterprise Notification to notify</documentDesc>
                </documentHeader>
                <notificationRequest>
                        <notificationRequestHdr>
                                <originationDateTime/>
                                <isRegistered/>
                                <notificationRgstdDesc/>
                                <requestOriginator/>
                                <recipientList/>
                        </notificationRequestHdr>
                        <notificationRequestBody>
                                <notificationRequestDtlList/>
                        </notificationRequestBody>
                </notificationRequest>
        </document>
</myCompanyDocument>);

my @chunks =  ( 
q(
<notificationRequestDtl>
        <notificationRequestDtlHdr>
                <priority>HIGH</priority>
                <severity>LOW</severity>
                <reference />
        </notificationRequestDtlHdr>
        <notificationRequestDtlBody>
        <requestDetail><realm>TEST</realm><status>Succeeded</status><user>spbmb</user><date>2010-04-02</date><time>01:01:01</time><asset>LoginEAR.ear</asset><cell>Infra</cell><cluster>Login_TESTA</cluster><failingScript>N/A</failingScript><failureMessage>N/A</failureMessage></requestDetail></notificationRequestDtlBody>
</notificationRequestDtl>
),
q(
<notificationRequestDtl>
        <notificationRequestDtlHdr>
                <priority>MEDIUM</priority>
                <severity>HIGH</severity>
                <reference />
        </notificationRequestDtlHdr>
        <notificationRequestDtlBody>
        <requestDetail><realm>ANOTHER TEST</realm><status>Succeeded</status><user>spbmb</user><date>2010-04-02</date><time>01:01:01</time><asset>LoginEAR.ear</asset><cell>Infra</cell><cluster>Login_TESTA</cluster><failingScript>N/A</failingScript><failureMessage>N/A</failureMessage></requestDetail></notificationRequestDtlBody>
</notificationRequestDtl>
) );


my $xp = XML::XPath->new(xml => $xml);
my $nodeset = $xp->find("//notificationRequestDtlList[1]") || die "can't find the detail list node";
my $node = $nodeset->get_node(1);  # want the node-- not the set

for my $chunkxml (@chunks) {
	my $xpchunk = XML::XPath->new(xml => $chunkxml)->find("/")->get_node(1);  # return the xml as a node
	$node->appendChild($xpchunk);  # append it to our details
}

print $xp->find("/")->get_node(1)->toString;

Open in new window

0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Browsing the questions asked to the Experts of this forum, you will be amazed to see how many times people are headaching about monster regular expressions (regex) to select that specific part of some HTML or XML file they want to extract. The examp…
Article by: Tammy
MySQLTuner is a script written in Perl that allows you to review a MySQL installation quickly and make adjustments to increase performance and stability. The current configuration variables and status data is retrieved and presented in a brief forma…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
Six Sigma Control Plans
Suggested Courses

601 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question