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

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

本文介绍了如何使用Powershell循环创建XML文件的元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Im going to create xml file. The element of the xml I pick from .ini file. I have .ini file more than 1.I try this, but still can create only 1 element.

.ini文件中有2种类型的内容文件.1st.

There are 2 kind of type content file in my .ini file.1st.

[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种类型.1st.

My expectation output of XML, will be there are 2 type.1st.

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

第二.

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

我到目前为止编写的代码:

The code I wrote so far :

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

任何人都可以帮助.忠告和解决方案表示赞赏.谢谢

Anyone can help please. Advices and solution really appreciated. Thank you

推荐答案

这是您的操作方法:

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

  • ^
  • 匹配行的开头
  • \[查找第一个[括号
  • 使用(.+)
  • 在组中一次或多次匹配任何字符
  • 将最后一个括号]\]匹配,并以$结束该行.
  • Match start of the line with ^,
  • Finds the first [ bracket with \[,
  • Matches any character once or more in a group with (.+),
  • Matches the last bracket ] with \] and ends the line with $.

制作一个正则表达式以匹配键和值.这可能类似于^(.+?)\s*=\s*(.*)$.

Make a Regex to match keys and values. This could be something like ^(.+?)\s*=\s*(.*)$.

  • ^
  • 匹配行的开头
  • 使用(.+?)
  • 查找任意字符的键一次或无限次
  • =符号与\s*=\s*
  • 之间匹配零个或多个空格
  • (.*)匹配组中的零个或多个字符,并以$结束行.
  • Match the start of the line with ^,
  • Finds keys with any character one or unlimited times with (.+?),
  • Matches zero or more whitespace between an = sign with \s*=\s*
  • Matches zero or more characters in a group with (.*) and ends the line with $.

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

With the above in mind, we can make a function to return the .ini file structure as nested hash tables. I use the -File and -Regex switches from switch to read the file and search for regex patterns. You can have a look at about_Switch for more information.

但是,这可能必须进行更多错误检查,例如处理注释和无效条目.我已经做了一些适用于上述.ini文件的操作.

However, this will probably have to have more error checking, such as dealing with comments and invalid entries. I've just made something that will work for the above .ini files.

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文件.

Then you could iterate your two .ini files, lets say first.ini and second.ini. and create the XML files for both of them using the hash tables returned from 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)
}

first.xml

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

second.xml

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

这篇关于如何使用Powershell循环创建XML文件的元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-29 02:01