【问题标题】:How to create element of XML file with looping using powershell?如何使用powershell循环创建XML文件的元素?
【发布时间】:2020-08-06 06:37:19
【问题描述】:

我要创建 xml 文件。我从 .ini 文件中选择的 xml 元素。我的 .ini 文件超过 1 个。 我试试这个,但仍然只能创建 1 个元素。

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

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

[Controller1]
Desc = Embedded Intel RAID

[Controller2]
Desc = Intel Optane Device

第二个。

[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>

第二个。

<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】:

    你可以这样做:

    • 制作一个正则表达式来匹配标题。这可能类似于^\[(.+)\]$

      • 将行首与^匹配,
      • \[找到第一个[括号,
      • 将组中的任何字符与(.+)匹配一次或多次,
      • 将最后一个括号]\] 匹配,并以$ 结束行。
    • 制作一个正则表达式来匹配键和值。这可能类似于^(.+?)\s*=\s*(.*)$

      • 将行首与^匹配,
      • 使用(.+?) 查找任意字符一次或无限次的键,
      • = 符号与\s*=\s* 之间匹配零个或多个空格
      • 将组中的零个或多个字符与(.*) 匹配,并以$ 结束行。

    考虑到上述情况,我们可以创建一个函数以将.ini 文件结构作为嵌套哈希表返回。我使用switch 中的-File-Regex 开关来读取文件并搜索正则表达式模式。您可以查看about_Switch 了解更多信息。

    但是,这可能需要进行更多的错误检查,例如处理 cmets 和无效条目。我刚刚做了一些适用于上述.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。并使用从Get-IniFile 返回的哈希表为它们创建 XML 文件。

    $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)
    }
    

    first.xml

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

    second.xml

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-28
      • 2021-12-04
      • 1970-01-01
      • 2020-08-02
      • 2013-10-24
      相关资源
      最近更新 更多