#xml #powershell
Вопрос:
Я планировал создать конфигурационный xml-файл для своего небольшого приложения powershell. Для этого я создаю процедуру инициализации, которая опрашивает пользователя, а затем генерирует файл конфигурации на основе введенных им данных. Основная программа будет получать данные из нее, и не каждый раз, когда она запускается. Процедура должна создать файл с примерно такой структурой:
<CamInfoSettings>
<Application>
<AppFolder>C:Temp1</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:Temp1Section1.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>
Я узнал, как создавать xml, используя примеры с этого сайта или из Интернета, но я застрял в той части, где мне нужно создать несколько дочерних элементов в разделе SectionIpNetworks.
Поскольку существует множество сетей, которые можно использовать с основной программой, я хотел бы создать файл именно с такой структурой.
Я остановился на том факте, что я могу создать одну или несколько сетей, но я не могу присвоить им атрибут «идентификатор» и создавать дочерние элементы в каждой сети.
Я прошу вас помочь с небольшим примером. мой код процедуры запрашивает у пользователя количество сетей, а затем в цикле он должен добавлять элементы. Ниже приведен пример кода, который создает ветви, но дальнейшая работа застопорилась. Скорее всего, я совершаю какую-то глобальную ошибку, в которой я не мог разобраться в течение нескольких дней. Мой код:
$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
}
Комментарии:
1. «Я планировал создать xml — файл конфигурации для своего небольшого приложения powershell» — могу ли я предложить вместо этого использовать JSON в качестве формата файла конфигурации? JSON было бы намного проще создавать и намного проще поддерживать.
2. мое основное приложение будет использовать запросы api для оборудования, и все они возвращаются в xml, поэтому я хотел использовать xml. конечно, нет никакой разницы в том, в каком формате будет файл конфигурации и имеет ли он структуру. Но если бы я оставил структуру, как описано выше, она была бы более читабельной.
3. «Более читабельный» по сравнению с чем? (Вам также нужно подумать о удобочитаемости вашего кода, и это уже плохое начало.)
Ответ №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 hash ( @{}
) to [pscustomobject]
. Но вы можете видеть, как легко собственные структуры данных PowerShell преобразуются в JSON.
(3) -Depth
Параметр важен. Кроме того, PowerShell имеет несколько нетрадиционное представление о том, как форматировать JSON, но с этим можно справиться.
В качестве общего совета: Не храните самоочевидные вещи в качестве параметров конфигурации. Вам не нужно значение, хранящее количество секций или количество сетей. Если вам нужно знать, сколько их там, посчитайте их:
$numSections = $config.Sections.Length
Хранение этих вещей приводит к ошибкам только в том случае, если они по какой-либо причине не синхронизированы с реальностью.
Комментарии:
1. Я думаю, вы правы, я реорганизую свою конфигурацию в JSON.
2. @ВладимирКостяник Есть одна небольшая проблема, о которой вам нужно знать-добавить новые ключи к объекту непросто. Когда вы
$test = '{"a": 1}' | ConvertFrom-Json
попытаетесь$test.b = 2
, произойдет сбой с ошибкой «Свойство» b «не может быть найдено на этом объекте». ошибка. Используйте$test | Add-Member NoteProperty -Name "b" -Value 2
для этого. (Опять же, файлы конфигурации, как правило, имеют предопределенную, фиксированную структуру — вам не нужно часто динамически добавлять новые свойства.)3. Спасибо, @Tomalak! Ваш совет действительно классный. Мой код для xml содержит 20 строк, для JSON — 5. Спасибо
4. @ВладимирКостяник You’re welcome! Рад слышать, что все так хорошо получилось!