【问题标题】:How to create a multi-level xml file using Powershell如何使用 Powershell 创建多级 xml 文件
【发布时间】:2021-12-04 21:26:12
【问题描述】:

我打算为我的小型 powershell 应用程序创建配置 xml 文件。 为此,我创建了一个初始化程序来轮询用户,然后根据他输入的数据生成一个配置文件。主程序会从中获取数据,而不是每次启动时。 该过程应该创建一个类似以下结构的文件:

<CamInfoSettings>
  <Application>
    <AppFolder>C:\Temp\01</AppFolder>
    <PictureFolder>images</PictureFolder>
    <LogFiles>CamInfo.log</LogFiles>
  </Application>
  <Sections>
    <Count>1</Count>
    <Section id="1">
      <Name>FirstSection Name</Name>
      <Description>FirstSection Description</Description>
      <SectionNetworksCount>2</SectionNetworksCount>
      <FileName>C:\Temp\01\Section1.config</FileName>
      <SectionIpNetworks>
          <SectionIpNetwork id="1">
              <Network>192.168.12.</Network>
              <StartIp>22</StartIp>
              <FinishIp>99<FinishIp>
          <SectionIpNetwork id="2">
              <Network>192.168.13.</Network>
              <StartIp>1</StartIp>
              <FinishIp>254<FinishIp>
      </SectionIpNetworks>
    </Section>

我学习了如何使用来自该站点或 Internet 的示例创建 xml,但我陷入了需要在 SectionIpNetworks 部分创建多个子元素的部分。 由于有许多网络可以与主程序一起使用,我想创建一个具有这种结构的文件。 我确定我可以创建一个或多个网络,但我不能为它们分配“id”属性并在每个网络中创建子节点。

我请你帮忙举一个小例子。 我的程序代码询问用户网络的数量,然后在一个循环中他必须添加项目。下面是一个创建分支的代码示例,但进一步的工作停滞不前。很可能我犯了某种全球性的错误,我已经好几天没弄明白了。 我的代码:

$SectionEnumber = [int]$Configfile.CamInfoSettings.Sections.Count + 1
$Configfile.SelectSingleNode("CamInfoSettings/Sections/Count").InnerText = $SectionEnumber       
$newSectionNode = $Configfile.CamInfoSettings.Sections.AppendChild($Configfile.CreateElement("Section"))
$newSectionNode.SetAttribute("id",$SectionEnumber)
$newSectionName = $newSectionNode.AppendChild($Configfile.CreateElement("Name"))
$newSectionName.AppendChild($Configfile.CreateTextNode($SectionName)) | Out-Null
$newDescription = $newSectionNode.AppendChild($Configfile.CreateElement("Description"))
$newDescription.AppendChild($Configfile.CreateTextNode($SectionDescription)) | Out-Null
$newSegmentsCount = $newSectionNode.AppendChild($Configfile.CreateElement("SectionNetworksCount"))
$newSegmentsCount.AppendChild($Configfile.CreateTextNode($SectionNetworksCount)) | Out-Null
$newFileName = $newSectionNode.AppendChild($Configfile.CreateElement("FileName"))
$newFileName.AppendChild($Configfile.CreateTextNode($WritePath + "\" + "Section$SectionEnumber.config")) | Out-Null
$newSectionNode.AppendChild($Configfile.CreateElement("SectionNetworks")) | Out-Null
$newNetworksNode =  $Configfile.SelectSingleNode("CamInfoSettings/Sections/Section[@id=$SectionEnumber]/SectionNetworks")
$newNetworksNode.SetAttribute("count",$SectionNetworksCount)
foreach ($item in 1..$SectionNetworksCount) {
$newNetworksNode.AppendChild($Configfile.CreateElement("SectionNetwork")) |Out-Null

Here i must create Elements for SectionIpNetwork and set attruibute id=$item
}

【问题讨论】:

  • “我打算为我的小型 powershell 应用程序创建一个配置 xml 文件” - 我可以建议使用 JSON 作为配置文件格式吗? JSON 会更容易构建和维护。
  • 我的主应用程序会使用api请求设备,它们都以xml返回,这就是我想使用xml的原因。当然,配置文件的格式以及是否具有结构都没有区别。但如果我按照上面描述的那样保留结构,它会更易读。
  • “更具可读性”与什么相比? (您还需要考虑代码的可读性,而这已经是一个糟糕的开始。)

标签: xml powershell


【解决方案1】:

我认为当您尝试将 XML 保留为您的配置格式时,您会受到很大的伤害。我建议切换到 JSON。

这相当于你的配置结构。

{
    "Application": {
        "AppFolder": "C:\\Temp\\01",
        "PictureFolder": "images",
        "LogFiles": "CamInfo.log"
    },
    "Sections": [{
        "id": 1,
        "Name": "FirstSection Name",
        "Description": "FirstSection Description",
        "FileName": "C:\\Temp\\01\\Section1.config",
        "SectionIpNetworks": [{
                "id": 1,
                "Network": "192.168.12.",
                "StartIp": 22,
                "FinishIp": 99
            },
            {
                "id": 2,
                "Network": "192.168.13.",
                "StartIp": 1,
                "FinishIp": 254
            }
        ]
    }]
}

阅读起来很简单:

$config = Get-Content config.json -Raw -Encoding UTF8 | ConvertFrom-Json

访问它很简单(1)

$appFolder = $config.Application.AppFolder

$section = $config.Sections | Where id -eq 1

改变它很简单(2)

# adding an array entry
$section.SectionIpNetworks += [pscustomobject]@{
    id = 3
    Network = "192.168.14."
    StartIp = 1
    FinishIp = 254
}

# removing an array entry
$section.SectionIpNetworks = $section.SectionIpNetworks | Where id -ne 1

写起来很简单(3)

$config | ConvertTo-Json -Depth 10 | Set-Content config.json -Encoding UTF8

(1) 在这种情况下,该部分实际上对 XML 和 JSON 的工作方式完全相同。

(2) 这里需要从 PowerShell 哈希 (@{}) 转换为 [pscustomobject]。但是您可以看到原生 PowerShell 数据结构转换为 JSON 是多么容易。

(3)-Depth 参数很重要。此外,PowerShell 对如何格式化 JSON 有一个非常规的想法,但它是易于管理的。


作为一般提示:不要将不言自明的东西存储为配置选项。您不需要存储部分计数或网络计数的值。如果你想知道有多少,数一数:

$numSections = $config.Sections.Length

存储这些东西只会在它们因任何原因与现实不同步时导致错误。

【讨论】:

  • 我认为你是对的,我将我的配置重新组织为 JSON。
  • @ВладимирКостяник 您需要注意一个小问题 - 向对象添加 new 键并不简单。当您有 $test = '{"a": 1}' | ConvertFrom-Json 时,尝试 $test.b = 2 将失败,并显示 "在此对象上找不到属性 'b'。" 错误。为此使用$test | Add-Member NoteProperty -Name "b" -Value 2。 (再说一遍,配置文件往往有一个预定义的、固定的结构——你不应该经常需要动态添加新属性。)
  • 谢谢你,@Tomalak!你的建议真的很酷。我的 xml 代码包含 20 个字符串,用于 JSON - 5。谢谢
  • @ВладимирКостяник 不客气!很高兴听到效果这么好!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-29
  • 1970-01-01
  • 2020-08-06
  • 1970-01-01
  • 2022-07-06
  • 2019-11-02
  • 2013-09-16
相关资源
最近更新 更多