Удаление дочернего узла в файле XML - PullRequest
0 голосов
/ 20 сентября 2018

Допустим, у меня есть этот XML:

    <?xml version="1.0" encoding="utf-16"?>
    <GPO xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.microsoft.com/GroupPolicy/Settings">
      <Identifier>
        <Identifier xmlns="http://www.microsoft.com/GroupPolicy/Types">{0afca021-554a-49cf-adab-2b6241895145}</Identifier>
      </Identifier>
      <Name>DefaultName</Name>
      <IncludeComments>true</IncludeComments>
      <CreatedTime>2012-08-08T18:20:05</CreatedTime>
      <ModifiedTime>2018-09-05T20:23:59</ModifiedTime>
      <ReadTime>2018-09-19T11:02:17.4750654Z</ReadTime>
     </GPO>

С помощью PowerShell, как я могу удалить узлы CreatedTime и ModifiedTime?

Что меня отталкивает, так это проблема пространства имен с элементом GPO,

Вот что у меня есть:

[xml]$xml = Get-Content "C:\temp\x.xml"
$parent_xpath = '//GPO'
$nodes = $xml.SelectNodes($parent_xpath)
$nodes
$nodes | % {
        $child_node = $_.SelectSingleNode('CreatedTime')
        $_.RemoveChild($child_node) | Out-Null
}
 $xml.Save("C:\temp\x-2.xml")
exit

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

Вы можете вызвать родительский узел, пройти через каждый дочерний узел, а затем удалить из родительского узла.Вы можете определить родителя с помощью «Node.ChildNode.ChildNode»

Написал для вас быструю функцию

function Remove-ChildNodes([xml]$FullXML, [string]$ParentNode, [string[]]$NodeNames){
    return ($xml.$ParentNode.ChildNodes | ?{ $NodeNames -contains $_.Name }) | %{[void]$_.ParentNode.RemoveChild($_)}
}

А вот рабочая копия

[xml]$xml=@"
<?xml version="1.0" encoding="utf-16"?>
    <GPO xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.microsoft.com/GroupPolicy/Settings">
      <Identifier>
        <Identifier xmlns="http://www.microsoft.com/GroupPolicy/Types">{0afca021-554a-49cf-adab-2b6241895145}</Identifier>
      </Identifier>
      <Name>DefaultName</Name>
      <IncludeComments>true</IncludeComments>
      <CreatedTime>2012-08-08T18:20:05</CreatedTime>
      <ModifiedTime>2018-09-05T20:23:59</ModifiedTime>
      <ReadTime>2018-09-19T11:02:17.4750654Z</ReadTime>
     </GPO>
"@

function Remove-ChildNodes([xml]$FullXML, [string]$ParentNode, [string[]]$NodeNames){
    return ($xml.$ParentNode.ChildNodes | ?{ $NodeNames -contains $_.Name }) | %{[void]$_.ParentNode.RemoveChild($_)}
}

Remove-ChildNodes -FullXML $xml -ParentNode "GPO" -NodeNames "CreatedTime","ModifiedTime"
$xml.InnerXml
0 голосов
/ 20 сентября 2018

Рассмотрим XSLT , специализированный язык, предназначенный для преобразования файлов XML, который может обрабатывать пространства имен по умолчанию и удалять элементы без зацикливания.PowerShell может взаимодействовать с пространством имен * .NET System.Xml.Xsl для запуска сценариев XSLT 1.0.

В частности, в XSLT объявляется префикс для пространства имен по умолчанию, здесь используется gpo , затем запустите преобразование идентичности , чтобы скопировать весь документ как есть, и передайте пустые шаблоны для элементов CreatedTime и ModifiedTime .Поэтому в любом месте эти элементы, отображаемые в документе, будут удалены без зацикливания или ссылки на родительские теги.Кроме того, при таком подходе, если вам нужно внести другие конструктивные изменения в XML, вы легко можете сделать это в сценарии XSLT, не касаясь сценария PowerShell.

XSLT (сохранить как.xsl-файл, специальный XML-файл)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:gpo="http://www.microsoft.com/GroupPolicy/Settings">
  <xsl:output indent="yes" method="xml"/>
  <xsl:strip-space elements="*"/>

  <!-- IDENTITY TRANSFORM -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- EMPTY TEMPLATES TO REMOVE -->
  <xsl:template match="gpo:CreatedTime|gpo:ModifiedTime"/>

</xsl:stylesheet>

XSLT Demo

PowerShell

$xslt = New-Object System.Xml.Xsl.XslCompiledTransform;

$xslt.Load("C:\Path\To\XSLT_Script.xsl");
$xslt.Transform("C:\Path\To\Input.xml", "C:\Path\To\Output.xml");
...