views:

485

answers:

3

Hi All,

I am writing a PowerShell wrapper for an existing Perl script. The Perl script is fed a couple of parameters and goes off and configures all our HP iLO devices for us, and returns the results in an XML format. The problem is the result comes out as one big blob of multiple XML statements ie:

$strResult = & "perl locfg.pl -s $iloInterface -f $configXML"

<?xml version="1.0"?>
<RIBCL VERSION="2.22"/>
    <RESPONSE
    STATUS="0x0000"
    MESSAGE='No error'
     />
</RIBCL>

<?xml version="1.0"?>
<RIBCL VERSION="2.22"/>
<RESPONSE
    STATUS="0x0000"
    MESSAGE='No error'
     />
</RIBCL>

etc.

Attempting to then cast the $strResult to XML results in Error: "There are multiple root elements

Does anyone have any thoughts on how I can split up these XML statements in PowerShell to make them valid? I was thinking maybe a "dummy" root element may be in order? Or should I be looking at tweaking the underlying Perl script?

A: 

Either tweaking the Perl or wrapping a root element around it should work. You could also split the returned value on the empty lines then create an array of XML objects.

Actually I'm not sure that a root element would work since each of those bits have a version node in there.

EBGreen
+1  A: 

I think it's easiest to split at the XML declaration <?xml .... First of all, you're getting the XML not as a single string, but as a String[], so we need join these:

[string]::Join("`n", $strresult)

ETA: The join operator was new in Powershell 2, I changed it using [string]::Join.

We can then split them up at the XML declaration:

-split "<\?xml"

Now we get multiple strings back, each of which is either empty (for the first one) or contains XML with a mutilated declaration. First let's strip out the empty ones:

| ? { $_.Trim() }

This will look whether the string is non-empty after removing all whitespace. Now we need to add the declaration back in we stripped:

| % { "<xml$_" }

And now we can also cast to XML:

| %{ [xml] $_ }

Note however, that your original XML was wrong to begin with. <RIBCL VERSION="2.22"/> is a self-closing root element and after the RESPONSE element you're closing the RIBCL element again. When I remove the / at the end of the opening RIBCL element all works fine:

PS Home:\> (gc t.txt) -join "`n" -split "<\?xml" |
>> ? { $_.Trim() } |
>> % { "<?xml$_" } |
>> % { [xml] $_ }
>>

xml                                                         RIBCL
---                                                         -----
version="1.0"                                               RIBCL
version="1.0"                                               RIBCL

ETA: If you can count on it, then it's certainly easier to split at the empty line, though:

[string]::Join("`n", $strResult) -split "`n`n"
Joey
Thanks. This is certainly what I am looking for :) I'm getting thrown in the deep end a bit with powershell, but I think its fantastic compared to vbscript ;)I'll give this a go when I get to work tomorrow :)
Ben Short
You can probably also just split on the empty line, though, with `-split "`n`n"` but I didn't know whether that line would be always empty between the individual XML segments and whether no empty lines would appear inside them. So I chose to split at a point where it's clearly an XML starting point.
Joey
Hi Johannes, Trying to replicate above, I get the following error: PS D:\iLO Scripts> (gc .\xmlsample.txt) -join "`n" -split "<\?xml" | You must provide a value expression on the right-hand side of the '-' operator. At line:1 char:23 + (gc .\xmlsample.txt) -j <<<< oin "`n" -split "<\?xml" |
Ben Short
Oh, `-join` was a new addition in Powershell 2, my apologies. I'll rewrite that part.
Joey
Thanks. All working well now :)
Ben Short
A: 

Another way that works for me is to wrap a root element around the entire output and remove the versioning elements. This does parse correctly for me using the SAX parser for java