Функция XML по значению?

У меня есть функция, которая возвращает хеш-таблицу с различными ключами, один из которых — XML. У меня также есть код, предназначенный для проверки этого XML перед его возвратом. Тем не менее, у меня есть то, что сначала казалось проблемами загрязнения конвейера, но я изолировал это от кода замены XML.

Итак, изначально я делал всю замену XML напрямую с ключом в хэше возврата, используя $result.xml. Однако с тех пор я изменил код, чтобы использовать отдельную переменную:

$revisedXml = $result.xml
$oldnode = $revisedXml.selectSingleNode("/Definitions/InstallTypes/InstallType[@id='$supersedes']")
$newnode = $temp.xml.selectSingleNode("/Definitions/InstallTypes/InstallType[@id='$supersedes']")
$importNode = $revisedXml.ImportNode($newnode, $true)
$oldnode.ParentNode.AppendChild($importNode)
$oldnode.ParentNode.RemoveChild($oldnode)

Однако любая из этих двух последних строк приводит к взрыву хэша $return. Это заставило меня подумать, что я помню что-то о том, что XML существует по ссылке, а не по значению, поэтому на самом деле я напрямую обращаюсь к XML, просто через новый указатель, и то, что я меняю, каким-то образом взрывает всю переменную хеш-таблицы, которая также ссылается на XML. Это звучит правильно, или я уже иду по неверному пути?

Также и, возможно, связанные. Что я в конечном итоге хочу сделать, так это найти конкретный узел в $result.xml и в другом $temp.xml (загруженном из разных файлов) и, если он будет найден, заменить узел в $result на узел из $temp. Я пытался использовать ReplaceChild(), но это, похоже, не работает, возможно, проблема с PowerShell 2.0.

Итак, с этими двумя битами данных есть ли лучший способ пересмотреть XML и есть ли способ заставить его работать с функцией, которая правильно передает XML по значению? FWIW, я рефакторинг, чтобы избежать глобальной переменной XML, которую я успешно использовал. Обычно я не люблю глобальные переменные, но, возможно, это тот случай, когда мне просто нужно их использовать?

EDIT: Итак, пытаемся изолировать проблему и сталкиваемся с новыми проблемами. Здесь я пытаюсь создать две XML-переменные в функции, заменить узел из одной переменной узлом из другой и передать его обратно из функции, затем написать в консоль, чтобы убедиться, что результат правильный (разница в том, что SilentModeID должен быть 9). Проблема в том, что две строки здесь не работают. Пробовал и с одинарными кавычками, но все равно выдает ошибки. Не совсем яблоки к яблокам, так как в моем реальном коде я не использую здесь строки, я читаю XML из файлов, но для целей обсуждения это казалось лучшим способом. Итак, первый новый вопрос, что, черт возьми, я делаю не так со строками здесь? Как только это заработает, мы сможем увидеть, нарушается ли передача XML обратно таким же образом.

function Write-PxXmlToConsole ($xml) {
    $stringWriter = New-Object System.IO.StringWriter
    $xmlWriter = New-Object System.Xml.XmlTextWriter $stringWriter
    $xmlWriter.Formatting = "indented"
    $xml.WriteTo($xmlWriter)
    $xmlWriter.Flush()
    $stringWriter.Flush()
    Write-Host $stringWriter.ToString()
}


function Import-PxXml {

$result = @{
    success = $true
    xml = $null
    log = $null
}

[xml]$assets = @"
<?xml version="1.0"?>
<Definitions>
<InstallTypes>
<InstallType id="deployment">
<SilentModeID>1</SilentModeID>
</InstallTypes>
</InstallType>
</Definitions>
"@

[xml]$newAssets = @"
<?xml version="1.0"?>
<Definitions>
<InstallTypes>
<InstallType id="deployment">
<SilentModeID>9</SilentModeID>
</InstallType>
</InstallTypes>
</Definitions>
"@

$nodeName = 'deployment'

$oldnode = $assets.selectSingleNode("/Definitions/InstallTypes/InstallType[@id='$nodeName']")
$newnode = $newAssets.selectSingleNode("/Definitions/InstallTypes/InstallType[@id='$nodeName']")
$importNode = $assets.ImportNode($newnode, $true)

$oldnode.ParentNode.AppendChild($importNode)
$oldnode.ParentNode.RemoveChild($oldnode)

$result.xml = $assets
$result.log = 'Crossed Fingers'

return $result
}


$test = Import-PxXml
Write-PxXmlToConsole $test.xml

person Gordon    schedule 20.03.2016    source источник
comment
любая из этих последних двух строк является причиной взрыва хэша $return Каким образом?   -  person Mathias R. Jessen    schedule 20.03.2016
comment
Это создает видимость проблемы с поврежденным конвейером. Если я перебираю $return в конце функции, это выглядит правильно, но перебирая переменную, которая получает функцию, я получаю то, что кажется одним ключом, без имени и без значения, но с .count равным 3 keys, а не четыре ключа, которые находятся в хэше $return в функции. Rem эти две строчки в функции и все работает в вызывающем коде. Но, конечно же, XML не меняется, так что это не полезный код, а просто рабочий код.   -  person Gordon    schedule 20.03.2016
comment
Существует куча другого кода, поэтому я пытаюсь изолировать проблему настолько, чтобы опубликовать полезный пример без сотен лишних строк. Но это само по себе занимает кучу времени.   -  person Gordon    schedule 20.03.2016
comment
И почему именно фраза «Любое понимание высоко ценится» почему-то запрещена?   -  person Gordon    schedule 20.03.2016
comment
@Gordon Эта фраза на самом деле не запрещена, но такая ерунда немного не одобряется SO, потому что она не добавляет ничего существенного к вопросу. Конечно вы приветствуете любое понимание, поэтому вы задали вопрос. То же самое касается подписи вашего вопроса или написания короткой биографии вверху, как люди часто считают необходимым сделать. Сопротивляйтесь стремлению к светской беседе и сосредоточьтесь на необработанных фактах.   -  person Tomalak    schedule 20.03.2016
comment
PowerShell имеет тенденцию преобразовывать типы на лету по мере необходимости. Я бы попытался явно объявить $test как [xml]$test и посмотреть, имеет ли это какое-то значение. Или сначала проверьте тип $test после того, как он получил результат функции, чтобы увидеть, во что он превратился. Вы также можете явно указать промежуточные результаты, объявив переменные с префиксом [System.Xml.XmlElement].   -  person Martin Maat    schedule 20.03.2016


Ответы (1)


Метод RemoveChild() и AppendChild() возвращает рассматриваемый дочерний узел, загрязняя ваш вывод.

Подавите вывод, и все будет в порядке:

$null = $oldnode.ParentNode.AppendChild($importNode)
$null = $oldnode.ParentNode.RemoveChild($oldnode)
person Mathias R. Jessen    schedule 20.03.2016
comment
О, ура! Загрязненный трубопровод в конце концов! Иногда мне действительно хотелось бы, чтобы был способ полностью отказаться от поведения конвейера, а затем снова включить его, когда это необходимо. А пока спасибо за переадресацию! ;) - person Gordon; 20.03.2016
comment
Да, мне тоже хочется строгого return время от времени, но всего не бывает :) - person Mathias R. Jessen; 20.03.2016
comment
Истинный дат. И на самом деле проблема заключалась в том, что я забыл первое правило PowerShell: это, вероятно, загрязнение конвейера. С этого момента, если у меня есть проблема, и я могу выделить ее в строку, мой первый шаг по устранению неполадок — добавить › $null в конец и посмотреть что происходит. - person Gordon; 20.03.2016
comment
Если вы можете использовать return, чтобы указать, что выводить, вы также можете сохранить каждый вывод функции/командлета в переменную или $null. Дополнительные слова не сломают ваш жесткий диск. :-) - person Frode F.; 20.03.2016