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

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;

LVL 1
BbouchAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

wilcoxonCommented:
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
BbouchAuthor Commented:
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
wilcoxonCommented:
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
clockwatcherCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
XML

From novice to tech pro — start learning today.