Forum Discussion

JB_SE_ED's avatar
JB_SE_ED
Copper Contributor
May 30, 2023

Need help extracting data from an XML file and adding it to a WDP file

Hi,

 

I'm working on a project that uses data from an XML file, which contains a unique file number(s) (Ex: E12345678-001-01) and a unit location(s) associated with that number (Ex: 1A)

 

Using the data from the XML it will then look for the unique file number(s) in a WDP file and add "='unit location'" (Ex: =1A) to the line above the file number. 

 

I am still learning how to script, so I had a friend help me write the majority of the script. Unfortunately, he is no longer available. So please be patient with me if I need further explanation on a solution.

 

My problem is this;

The script sometimes works, and sometimes it does not. When it doesn't work, it will populate some of the unit locations, but leave others with only an '=' and a blank unit location. It returns this error: 'Exception calling "Add" with "2" argument(s): "Item has already been added.'

 

I have done some research and found out that the issue may be with the 'add' command, but I am unsure of how to implement a solution into the current script. Any help would be appreciated. The full script is posted below.

 

# Open a form, and get the path from user input
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")

$foldername = New-Object System.Windows.Forms.FolderBrowserDialog
$foldername.SelectedPath = "C:\FO\" # Might be C:\FO\?

# You want them to select the line item here
if($foldername.ShowDialog() -eq "OK") { 
    $folder = $foldername.SelectedPath
    }
    
    
# Go back to the UIS folder for this FO to get the UIS XML
$path = (Split-Path -path $folder -Parent) + "\UIS"
$uisfile = Get-ChildItem $path -Filter *.UIS | Sort-Object -Descending -Property LastWriteTime | Select -First 1

# Load the XML
$uisxml= new-object -typename XML
$uisXML.load($uisfile.fullname)

# get an array of the drawings and locations
$DrawingArray = $uisXML.newdataset.unit | select-object -property drawing,location | where-object drawing -ne ""

# Create a hash so we can pull back out the drawings + locations later
$DrawingHash = new-object System.Collections.Hashtable
for($i=0; $i -lt $DrawingArray.Count; $i++){
     $DrawingHash.Add($DrawingArray[$i].Location,$DrawingArray[$i].Drawing)
}

# Read WDP from the folder, and get the latest written one (If it exists)
$wdpfile = Get-ChildItem $folder -Filter *.WDP | Sort-Object -Descending -Property LastWriteTime | Select -First 1
$wdpcontent = Get-Content $wdpfile.FullName



$lastunits = "" # Placeholder variable to keep track of what units we mentioned already

# Look through each line of the WDP file
for ($i=0; $i -lt $wdpcontent.Count; $i++){

     # if the line matches a drawing # from the list (Had to do the substring math for error prevention) 
     if($Drawingarray.Drawing.Contains(($wdpcontent[$i]+"               ").Substring(0,16))){ 
     
        # Pull which units match the drawings, and join them to the "##,##,##" format 
        $matchingunitsfromdrawinglist = ($DrawingHash.GetEnumerator() | Where-Object {$_.Value -eq ($wdpcontent[$i]+" ").Substring(0,16)} | Select-Object -Property "Name").name -join "," 
        
        # If this match is the same as the last one, don't do anything 
        #if ($matchingunitsfromdrawinglist -ne $lastunits){ 
        # Replace the current line with "=1A,2B" units, a line break, and the original line content 
        $wdpcontent[$i] = "=" + $matchingunitsfromdrawinglist + "`r`n" + $wdpcontent[$i] 
        
        # Update the placeholder for the next comparison 
        $lastunits = $matchingunitsfromdrawinglist 
        #} 
    }
}

# Write to the actual file.
$wdpcontent | Set-Content $wdpfile.FullName
  • LainRobertson's avatar
    LainRobertson
    Silver Contributor

    JB_SE_ED 

     

    Hi.

     

    In a HashTable, the key must be unique - i.e. you cannot add the same key value twice.

     

    I've reproduced the error you're seeing below, after which you can see how to use the ContainsKey() method of the HashTable class to check if a value already exists in a couple of additional examples.

     

     

    You can read more about the methods and properties available on the HashTable class here:

     

     

    Alternatively, you can leverage the "try {} catch {}" construct for a similar outcome.

     

    try
    {
        $h.Add("key1", "value1");
    }
    else
    {
        # Handle the error condition in here however, you see fit, such as
        # log it to the screen, one of the output streams, a file, or maybe just do nothing at all.
    }

     

    The bottom line is you will get errors if you try and add the same key more than once. How you handle that is up to you, but not handling that key uniqueness restriction is why you're seeing what you're seeing.

     

    Cheers,

    Lain

Resources