Ниже мой XML
<step>
<filename>tk1872_01\data\nx1872\nx1872_base_include_wrn.dat</filename>
<lookfor>W:\\ugs</lookfor>
<replace>C:\BM\ugs</replace>
</step>
<step>
<filename>NX1872_01\tools\checkReg.ps1</filename>
<lookfor>W:\\ugs</lookfor>
<replace>C:\BM\ugs</replace>
</step>
<step>
<filename>tk1872_01\data\nx1872\nx1872_base_include_wrn.dat</filename>
<lookfor>Y:\\CATIAcfgV5</lookfor>
<replace>C:\BM\CATIAcfgV5</replace>
</step>
Я пытаюсь сослаться выше XML, чтобы заменить строки в файлах, которые упомянуты в узле имени файла.
Например: я взял ссылку из XML для имени файла и его пути, например (tk1872_01\data\nx1872\nx1872_base_include_wrn.dat), затем я ищу «W:\ugs» и заменяю на «C:\BM\ugs». Это первый шаг для цикла foreach, но если вы видите 3-й шаг с тем же именем файла, но я ищу другую строку, но цикл foreach не выполнял замену второго вхождения с тем же именем файла.
Ниже приведен мой код, который я использую в Powershell.
$testXML = C:\test\settings.xml
[xml]$SpecialXMLFile = Get-Content $testXML
foreach ($step in $SpecialXMLFile.step)
{
$_aux = C:\temp
$_aux_dest = D:\temp
$srcfilename = $_aux + "\" + $step.filename
$destfilename = $_aux_dest + "\" + $step.filename
$strun = Get-Content $srcfilename
$strun -replace $step.lookfor, $step.change | Out-File -Encoding ascii $destfilename
}
Не могли бы вы сообщить мне, где я делаю неправильно, или мне нужно добавить еще несколько шагов?
Ваш опубликованный XML не соответствует пути, который вы указали в своем коде. Отсутствует [конфигурация], и в вашем коде есть элементы, которые не поясняют, что они есть или для чего они нужны. Наконец, вы действительно слишком усложняете этот вариант использования. XML/JSON являются родными для PowerShell, и у него есть командлеты для работы с ними.
@ Esperento57 Esperento57 да, извините, у меня есть еще два узла перед ступенчатыми узлами, о которых я забыл упомянуть.
@postanote Я использую файл XML, потому что я не хочу менять код каждый раз и каждый раз, когда я просто вношу изменения в XML, чтобы изменить свой код, и, соответственно, он будет вносить изменения в файлы конфигурации.
Итак, вы говорите, что никогда не знаете, что находится в файле XML? Вы можете просто настроить свой код для чтения XML, который вы получаете, и запрашивать, с каким узлом/значением вы хотите работать. В примере, который я предоставил, он просто захватывает основной узел конфигурации и отображает узел шага, с которым нужно работать. Затем вы используете эти параметры, чтобы делать то, что хотите. Вы можете подсказать что-либо из этого. Никаких изменений в базовом коде не требуется.
Пожалуйста, для ясности, отредактируйте свой вопрос и покажите нам желаемый результат. Мне очень неясно, что вы хотите заменить в файле.
@ Тео, я отредактировал свой вопрос, пожалуйста, просмотрите его и дайте мне знать, если вам нужны дополнительные разъяснения по этому поводу.
В продолжение моего комментария.
Get-Command -Name '*xml*'
# Results
<#
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet ConvertTo-Xml 3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet Export-Clixml 3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet Import-Clixml 3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet Select-Xml 3.1.0.0 Microsoft.PowerShell.Utility
#>
# Get specifics for a module, cmdlet, or function
(Get-Command -Name Select-Xml).Parameters
(Get-Command -Name Select-Xml).Parameters.Keys
Get-help -Name Select-Xml -Examples
Get-help -Name Select-Xml -Full
Get-help -Name Select-Xml -Online
Таким образом, почему бы не использовать собственный командлет Select-Xml, чтобы весело выбрать нужный узел и изменить его по мере необходимости.
Пример получения значений шага:
(@'
<configuration>
<step>
<filename>tk1872_01\data\nx1872_base_include_wrn.dat</filename>
<lookfor>W:\\ugs</lookfor>
<replace>C:\BM\ugs</replace>
</step>
<step>
<filename>NX1872_01\tools\checkReg.ps1</filename>
<lookfor>W:\\ugs</lookfor>
<replace>C:\BM\ugs</replace>
</step>
<step>
<filename>tk1872_01\data\nx1872\nx1872_base_include_wrn.dat</filename>
<lookfor>Y:\\CATIAcfgV5</lookfor>
<replace>C:\BM\CATIAcfgV5</replace>
</step>
</configuration>
'@ |
Select-Xml -XPath '//configuration').Node.step
# Results
<#
filename lookfor replace
-------- ------- -------
tk1872_01\data\nx1872_base_include_wrn.dat W:\\ugs C:\BM\ugs
NX1872_01\tools\checkReg.ps1 W:\\ugs C:\BM\ugs
tk1872_01\data\nx1872\nx1872_base_include_wrn.dat Y:\\CATIAcfgV5 C:\BM\CATIAcfgV5
#>
Затем замените чем угодно, используя то, что дано.
Не беспокойтесь, это случается. Это просто заставляет нас предполагать/догадываться о том, что происходит на самом деле, хотя это затрудняет ответ. Например, первые две строки в вашем коде избыточны, если только вы не запрашиваете это имя файла. $_aux* не определен нигде в вашем коде, поэтому то, что в нем находится, остается загадкой, а $step.change не имеет ссылки в XML. Итак, покажите больше своего XML, определения кода и ожидаемого результата.
@postnote, как я уже сказал, мне жаль, что я предоставил краткую информацию. Я снова отредактировал свой вопрос, указав правильную информацию, как вы просили. Я думаю, что мне не удалось заставить вас понять, что я хотел. моя реальная проблема заключается в том, что когда я выполняю шаг в Powershell в выходном файле, он изменяет только первое вхождение, которое является <lookfor>W:\\ugs</lookfor><replace>C:\BM\ugs</replace></step>, а не другим, которое <lookfor>Y:\\CATIAcfgV5</lookfor><replace>C:\BM\CATIAcfgV5</replace>
Я имею в виду, что если имя файла встречается два раза, оно считается только первым, а не вторым. он не заменяет строку во второй раз, когда присутствует одно и то же имя файла.
Спасибо за дальнейшее объяснение.
XML, который вы показываете, пропускает корневой элемент, поэтому я использовал это:
[xml]$xml = @"
<root>
<step>
<filename>tk1872_01\data\nx1872\nx1872_base_include_wrn.dat</filename>
<lookfor>W:\\ugs</lookfor>
<replace>C:\BM\ugs</replace>
</step>
<step>
<filename>NX1872_01\tools\checkReg.ps1</filename>
<lookfor>W:\\ugs</lookfor>
<replace>C:\BM\ugs</replace>
</step>
<step>
<filename>tk1872_01\data\nx1872\nx1872_base_include_wrn.dat</filename>
<lookfor>Y:\\CATIAcfgV5</lookfor>
<replace>C:\BM\CATIAcfgV5</replace>
</step>
</root>
"@
В реальной жизни вы хотели бы прочитать это из файла, используя
[xml]$xml = Get-Content -Path 'C:\test\settings.xml' -Raw
Дело в том, что на разных этапах один и тот же файл нужно корректировать, а в вашем коде этого не происходит, потому что файл считывается дважды, чтобы заменить только одно значение lookfor. Во второй раз считывается тот же (неизменный) исходный файл, и снова выполняется только одна замена.
Что вам нужно сделать, так это сгруппировать шаги, где имя файла одинаково, получить содержимое из этого файла только один раз и выполнить все необходимые замены для него. Затем выведите в новый файл по пути назначения.
$sourcePath = 'C:\temp'
$destination = 'D:\temp'
# combine the steps where the filenames are equal
# if your xml has a different named root, change that here
$xml.root.step | Group-Object filename | ForEach-Object {
# create the paths from the groups name
$fileIn = Join-Path -Path $sourcePath -ChildPath $_.Name
$fileOut = Join-Path -Path $destination -ChildPath $_.Name
# test if the output directory path for the file exists. If not create it first
$pathOut = [System.IO.Path]::GetDirectoryName($fileOut)
if (!(Test-Path -Path $pathOut -PathType Container)) {
$null = New-Item -Path $pathOut -ItemType Directory
}
# read the input file as a single multiline string
$content = Get-Content -Path $fileIn -Raw
foreach ($item in $_.Group) {
# replace as many times as needed
$content = $content -replace $item.lookfor, $item.replace
}
# are you sure about the -Encoding ascii ??
$content | Out-File -FilePath $fileOut -Encoding ascii
}
$SpecialXMLFile.configuration.replace.step должен быть $SpecialXMLFile.configuration.step.replace нет?