如何使用powershell创建XML文件的循环元素?

问题描述 投票:1回答:1

我打算创建xml文件。xml的元素是从.ini文件中挑选的,我有1个以上的.ini文件,我试了一下,但还是只能创建1个元素。我有1个以上的.ini文件,我试了一下,但还是只能创建1个元素。

我的.ini文件中有2种类型的内容文件。

[Product]
Name = NB A
String = Defaults and Exit

[Controller1]
Desc = Embedded Intel RAID

[Controller2]
Desc = Intel Optane Device

2.第二种类型的内容文件。

[Product]
Name = NB A
String = Defaults and Exit

[Controller1]
Desc = Embedded SATA 

我期望输出的XML,将有2种类型。

<Product Name=NB A>
      <Controller controllertype="raid">
      <Controller controllertype="optane">
</Product>

2.第二。

<Product Name=NB A>
      <Controller controllertype="raid">
</Product>

我写的代码,到目前为止。

$ProductListXML = "D:\TST.XML"
$driver = "D:\ver.xml" 


# get an XMLTextWriter to create the XML
$XmlWriter = New-Object System.XMl.XmlTextWriter($ProductListXML,$Null)

# choose a pretty formatting:
$xmlWriter.Formatting = 'Indented'
$xmlWriter.Indentation = 1
$XmlWriter.IndentChar = "`t"

# write the header
$xmlWriter.WriteStartDocument()

$xmlWriter.WriteStartElement('ProductList')
$xmlWriter.WriteAttributeString('Version', '200422a')

# load it into an XML object:
$xml = New-Object -TypeName XML
$xml.Load($driver)
$FamilyCode = $Xml.drivergroup.family | Select-Object -ExpandProperty Code

foreach ($fc in $FamilyCode)
{
    $FCDesc = $Xml.drivergroup.family | Where-Object { $_.code -eq "$fc" }| Select-Object -ExpandProperty description
    $SystemID = $Xml.drivergroup.family |  Where-Object { $_.code -eq "$fc" } | Select-Object -ExpandProperty Product | Select-Object -ExpandProperty systemid
    $IDSplit = $SystemID -split "/"

    $XmlWriter.WriteStartElement('Family')   
    $XmlWriter.WriteAttributeString('code', "$fc")
    $XmlWriter.WriteAttributeString('decription', "$FCDesc")

    foreach($sid in $IDSplit)
    {

        $ID = Get-ChildItem -path "D:\product\*$sid*" | Select-Object -ExpandProperty BaseName

        foreach ($id in $ID)
        {
            $File = Get-ChildItem -path "D:\product\*$id*"
            $ReadINI = @{} 
            Get-Content "$File" | ForEach-Object {
            $_.Trim()
            } | Where-Object {

            $_ -notmatch '^(;|$)'
            } | ForEach-Object {
            if ($_ -match '^\[.*\]$') {
            $section = $_ -replace '\[|\]'
            $ReadINI[$section] = @{}
            } else {
            $key, $value = $_ -split '\s*=\s*', 2
            $ReadINI[$section][$key] = $value    
            }
            }

            $ProductName = $ReadINI["Product"]["Name"]
            $TechType = $ReadINI["Controller1"]["Node"]
            if($TechType -eq "Intel")
            {
                $TechType = "Intel"
            }
            else{

                $TechType = "AMD"
            }
            $FactoryDefaultsString = $ReadINI["Product"]["String"]

            $YearPath = "D:\*.txt"
            $YearMapping = Select-String -Path $YearPath -Pattern "$id" 
            if($YearMapping -like "*2017*")
            {
                $Year = "2017"
            }
            elseif($YearMapping -like "*2018*")
            {
                $Year = "2018"
            }
            elseif($YearMapping -like "*2019*")
            {
                $Year = "2019"
            }
            elseif($YearMapping -like "*2020*")
            {
                $Year = "2020"
            }
            elseif($YearMapping -like "*2021*")
            {
                $Year = "2021"
            }

            $XmlWriter.WriteStartElement('Product')
            $XmlWriter.WriteAttributeString('Name', "$ProductName")
            $XmlWriter.WriteAttributeString('SSID', "$id")
            $XmlWriter.WriteAttributeString('TechType', "$TechType")
            $XmlWriter.WriteAttributeString('Year', "$Year")
            $XmlWriter.WriteAttributeString('FactoryDefaultsString', "$FactoryDefaultsString")

            $Controller2 = Select-String -Path $File -Pattern "Controller2" | Select-Object -ExpandProperty Filename
            foreach ($cont2 in $Controller2)
            {
                $file = Get-ChildItem "D:\product\$cont2"
                $ReadTechTp = @{} 
                Get-Content "$file" | ForEach-Object {
                $_.Trim()
                } | Where-Object {

                $_ -notmatch '^(;|$)'
                } | ForEach-Object {
                if ($_ -match '^\[.*\]$') {
                $section = $_ -replace '\[|\]'
                $ReadTechTp[$section] = @{}
                } else {
                $key, $value = $_ -split '\s*=\s*', 2
                $ReadTechTp[$section][$key] = $value    
                }
                }

                $Desc = $ReadTechTp["Controller2"]["Desc"]

                if($Desc -like "*RAID*" -or $Controller1 -like "*SATA*")
                {
                    $ControllerType = "RAID"
                }
                else{
                    $ControllerType = "OPTANE"
                }

                $XmlWriter.WriteStartElement('Controller')
                $XmlWriter.WriteAttributeString('ControllerType', "$ControllerType")

            }


            $xmlWriter.WriteEndElement()

        }



    }


    $xmlWriter.WriteEndElement()
}

    $xmlWriter.WriteEndElement()

# finalize the document:
$xmlWriter.WriteEndDocument()
$xmlWriter.Flush()
$xmlWriter.Close()

任何人都可以帮助,请。建议和解决方案真的很感激。谅谅

xml powershell loops
1个回答
1
投票

以下是你可以做的方法。

  • 做一个Regex来匹配头部。这可以是这样的 ^\[(.+)\]$.

    • 匹配线的开始与 ^,
    • 发现第一个 [ 托架与 \[,
    • 匹配组中的任何角色一次或多次,并与之匹配。(.+),
    • 匹配最后一个括号 ]\] 并在结尾处写上 $.
  • 做一个Regex来匹配键和值。这可以是这样的 ^(.+?)\s*=\s*(.*)$.

    • 匹配行的开始与 ^,
    • 通过以下方式查找任意字符的按键,一次或无限次 (.+?),
    • 匹配0个或更多的空格之间的空格。= 签有 \s*=\s*
    • 匹配组中0个或更多的字符。(.*) 并在结尾处写上 $.

考虑到上述情况,我们可以做一个函数来返回 .ini 文件结构为嵌套的哈希表。我使用的是 -File-Regexswitch 来读取文件并搜索regex模式。你可以看一下 about_Switch 获取更多信息。

然而,这可能会有更多的错误检查,例如处理评论和无效条目。我刚刚做了一些东西,将适用于上述的 .ini 文件。

function Get-IniFile {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$FilePath
    )

    $ini = [ordered]@{}

    switch -Regex -File $FilePath {

        # Match headers
        "^\[(.+)\]$" {
            $section = $Matches[1]
            $ini[$section] = [ordered]@{}
            continue
        }

        # Match key-value pairs
        "^(.+?)\s*=\s*(.*)$" {
            $name, $value = $matches[1..2]
            $ini[$section][$name] = $value
            continue
        }
    }

    return $ini
}

然后你可以迭代你的两个 .ini 文件,比方说 first.inisecond.ini......并使用从返回的哈希表为它们两个创建XML文件。Get-IniFile.

$iniFiles = "first.ini", "second.ini"

# Go through each .ini file
foreach ($file in $iniFiles) {

    # Create XML object to write to
    $xml = New-Object -TypeName System.Xml.XmlDocument

    # Get .ini file data into a hashtable
    $iniFileData = Get-IniFile -FilePath $file

    # Iterate first set of keys from hashtable
    foreach ($kvp in $iniFileData.GetEnumerator()) {

        # Create a product root key for the header
        $product = $xml.CreateElement($kvp.Key)

        # Iterate through key-value pairs
        foreach ($value in $kvp.Value.GetEnumerator()) {
            switch ($value.Name)
            {

                # If we found a name, this attribute belongs to the header
                "Name" {
                    $product.SetAttribute($value.Name, $value.Value)
                    $xml.AppendChild($product)
                    break
                }

                # Otherwise we found a descendent node
                "Desc" {

                    # Create descendent controller node
                    $controller = $xml.CreateElement("Controller")

                    # Determine how to set the attributes depending on the value
                    if ($value.Value -like "*RAID*" -or $value.Value -like "*SATA*") {
                        $controller.SetAttribute("controllertype", "raid");
                    } else {
                        $controller.SetAttribute("controllertype", "optane");
                    }

                    # Append controller node to product root node
                    $xml.Product.AppendChild($controller)
                    break
                }
            }
        }
    }

    # Save to XML file, using the name from the original file
    $filename = [System.IO.Path]::GetFileNameWithoutExtension($file)
    $xml.Save("{0}.xml" -f $filename)
}

第一.xml...........................................................................................................................................................................................................................................

<Product Name="NB A">
  <Controller controllertype="raid" />
  <Controller controllertype="optane" />
</Product>

二.xml

<Product Name="NB A">
  <Controller controllertype="raid" />
</Product>
© www.soinside.com 2019 - 2024. All rights reserved.