3

My regex works for picking up individual areas of the string content, but when I put it in the code to get the map of key-value pairs, the map is wrong. Any ideas?

The repeating content looks like this, with differing right side for alarmID like 12-5000, and the Key Name like LOAD_MEDIA:

<?xml version="1.0" encoding="utf-16"?>
<Configuration>
    <Key Name="Alarms">
    <Key Name="LOAD_MEDIA">
        <Value Name="AlarmID">12-5000</Value>
        <Value Name="blah">Dialog.Cut</Value>
        <Value Name="blah1"></Value>
        <Value Name="blah2">Dialog.Cancel</Value>
        <Value Name="blah3">false</Value>       
        <Value Name="blah4">true</Value>
        <Key Name="Sizes">
            <Key Name="57x">
                <Value Name="blah1">7</Value>
                <Value Name="blah2">9</Value>
                <Value Name="blah3">Dialog.57</Value>
            </Key>
            <Key Name="88">
                <Value Name="blah1">10</Value>
                <Value Name="blah2">10</Value>
                <Value Name="blah3">Dialog.88</Value>
            </Key>
            <Key Name="810">
                <Value Name="blah1">10</Value>
                <Value Name="blah2">12</Value>
                <Value Name="blah3">Dialog.810</Value>
            </Key>
            <Key Name="114">
                <Value Name="blah1">1</Value>
                <Value Name="blah2">1</Value>
                <Value Name="blah3">Dialog.114</Value>
            </Key>
            <Key Name="10">
                <Value Name="blah1">1</Value>
                <Value Name="blah2">2</Value>
                <Value Name="blah3">Dialog.10</Value>
            </Key>
        </Key>
    </Key>  
    <Key Name="LOAD_MEDIA2">
        <Value Name="AlarmID">12-5001</Value>
        <Value Name="blah">Dialog.Cut</Value>
        <Value Name="blah1"></Value>
        <Value Name="blah2">Dialog.Cancel</Value>
        <Value Name="blah3">false</Value>       
        <Value Name="blah4">true</Value>
        <Key Name="Sizes">
            <Key Name="57x">
                <Value Name="blah1">7</Value>
                <Value Name="blah2">9</Value>
                <Value Name="blah3">Dialog.57</Value>
            </Key>
            <Key Name="88">
                <Value Name="blah1">10</Value>
                <Value Name="blah2">10</Value>
                <Value Name="blah3">Dialog.88</Value>
            </Key>
            <Key Name="810">
                <Value Name="blah1">10</Value>
                <Value Name="blah2">12</Value>
                <Value Name="blah3">Dialog.810</Value>
            </Key>
            <Key Name="114">
                <Value Name="blah1">1</Value>
                <Value Name="blah2">1</Value>
                <Value Name="blah3">Dialog.114</Value>
            </Key>
            <Key Name="10">
                <Value Name="blah1">1</Value>
                <Value Name="blah2">2</Value>
                <Value Name="blah3">Dialog.10</Value>
            </Key>
        </Key>
    </Key>  
 </Key>
</Configuration>

..repeats format

For some reason, my errorMap returned is not even close to correct.

This is the code that is supposed to return key-value pairs in the $errorMap:

function Get-AlarmIDs{
    [cmdletbinding()]
    Param ([string]$fileContent)

    # create an ordered hashtable to store the results
    $errorMap = [ordered]@{}
    # process the lines one-by-one
    switch -Regex ($fileContent -split '\r?\n') {
        '[\t]+?<Key Name="(.*)">[\r?\n\s]+?<Value' { #match Key Name followed by Value  
            if(-not($matches[1] -match '[0-9]')) #use if it's not something like 57
            {
                $key = ($matches[1]).Trim()
            }
        }
        'AlarmID">(.*)<' {     #match AlarmID like 12-5700
                $errorMap[$key] = ($matches[1]).Trim()
        }
    }

    return $errorMap
}

I want the map to look like this:

LOAD_MEDIA, 12-5000
LOAD_MEDIA2, 12-3
...

I know that my test on regex101.com shows that my key and value separately pick up the lines needed, but when I put it together in the code, the map is all messed up:

[ordered dictionary:1]

[0]: [6,"12-5900"]   

I'm not sure where it's getting a 6 from, and the 12-5900 is about last in a repeating sequence that should have returned maybe 5 before the 12-5900.

I'm using powershell 5.1 and Visual Studio code.

Update:

I'm trying to do this the xml way, and not sure how to get out of the xml what I need.

[xml]$xmlElm = (select-xml -xpath / -path $fileNamePath).node #Get-Content $fileNamePath 
$xmlElem.Configuration.'Key Name'.'Key Name'.Value  #this doesn't print anything...shouldn't it?

Update2:

Trying some more...

[xml]$xmldocument = Get-Content $fileNamePath
$tmp1 = $xmldocument.ChildNodes.selectNodes("*")
$tmp2 = $xmldocument.ChildNodes.selectNodes("*/Key")
$tmp3 = $xmldocument.Key.Value.AlarmID[0] #this is indexing into null
$tmp4 = $xmldocument.Key.Value #this is null

Update3:

I'm trying what's in Santiago's answer, but get blank Value in the map.

[xml]$xmldocument = Get-Content $fileNamePath
   
$result = foreach($key in $xmldocument.Configuration.Key.Key)
{
    [pscustomobject]@{
        Key = $key.Name
        Value = $key.Value.Where{$_Name -eq 'AlarmID'}.'#text'
    }
}

Gives (blank values)

[0]: @{Key=LOAD_MEDIA; Value=}
[1]: @{Key=Load_MEDIA2; Value=}

I'm not sure what's different.

Update4:

$result = foreach($key in $xmldocument.Configuration.Key.Key)
{
        [pscustomobject]@{
            Key = $key.Name
            Value = $key.Value 
        }
}
return $result

When I look at $result, it looks like this:

[0]: @{Key=LOAD_MEDIA; Value=System.Object[]}
[1]: @{Key=Load_MEDIA2; Value=System.Object[]}
Michele
  • 3,617
  • 12
  • 47
  • 81
  • 4
    Any reason you wouldn't just load XML and then work using a powershell object instead? – Matt Feb 17 '22 at 20:00
  • For this, not really. I guess I'm doing it this way because my file types vary wildly and aren't always xml. This is probably the 20'th file I've parsed, and only my 2nd or 3rd that is actually xml. Is there a way to use the xml format? Especially given the repeated tags? – Michele Feb 17 '22 at 20:05
  • 1
    I agree with Matt, no reason to parse an Xml with regex. – Santiago Squarzon Feb 17 '22 at 20:59
  • I'm trying the xml way, and not sure how to find the tags, etc, to get all the Key Names like Load_Media, and AlarmID's like 12-5000 out. The outside tag is . – Michele Feb 17 '22 at 21:06
  • 1
    Could you edit your XML so that it is valid to be parsed with `XMLDocument`? You could add more than 1 alarm so we can reproduce it an help you with the parsing – Santiago Squarzon Feb 17 '22 at 21:10
  • 1
    It does not seem to be a valid XML, please verify it is correct or update it – Santiago Squarzon Feb 17 '22 at 21:41
  • I added end tag for key above last configuration end tag – Michele Feb 17 '22 at 21:48

1 Answers1

3

There is likely a better way than this but for now, this should help you get what you're looking for. Assuming you already have the XML loaded in a variable, in this case $xml:

$result = foreach($key in $xml.Configuration.Key.Key) {
    [pscustomobject]@{
        Key   = $key.Name
        Value = $key.Value.Where{$_.Name -eq 'AlarmID'}.'#text'
    }
}

$result using the XML in question should look like this:

Key         Value
---         -----
LOAD_MEDIA  12-5000
LOAD_MEDIA2 12-5001
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37