如何使用PowerShell在XML中注释节点?

14

有没有可能在XDocument中注释掉一个节点?

我有以下标签。

<abc key="test" value="samplevalue"></abc>

我不需要删除这个节点;我只想在XML文件中以注释的形式保留它。我可以使用类似以下的方式:

$node = $xml.selectSingleNode('//abc')
#$node.OuterXml.Insert(0,"#");
$node.$xml.Save("c:\test.xml")

但是,如果一个节点像这样分成两行

<abc key="test" value="sampleValue">
</abc>

那么我该如何处理这种情况?


每种编程语言都有自己的注释方式。在Powershell中是#,在C中是//,而XML有自己的方式 - 请参见下面的答案。不要假设在任何地方都是//#(无论你最常用哪个)。 - Victor Zakharov
4个回答

19
你可以创建一个注释节点,然后使用这些注释节点替换你的 abc 节点:

您可以简单地创建一个评论节点,并用这些评论节点替换您的abc节点:

$xml = [xml]@"
<root>
<abc key="test" value="samplevalue"></abc>
<abc key="sa" value="dsad">sda
</abc>
</root>
"@;

$xml.SelectNodes("//abc") | ForEach-Object { 
    $abc = $_;
    $comment = $xml.CreateComment($abc.OuterXml);
    $abc.ParentNode.ReplaceChild($comment, $abc);
}

$xml.Save(<# filename #>);

输出:

<root><!--<abc key="test" value="samplevalue"></abc>--><!--<abc key="sa" value="dsad">sda
</abc>--></root>

8

在XML中,注释使用<!---->完成。试试这个:

$xml = [xml]@"
<root>
<abc key="test" value="samplevalue"></abc>
<abc key="sa" value="dsad">sda
</abc>
</root>
"@

$node = $xml.selectSingleNode('//abc')
#OuterXML is read-only, so I took an alternative route
$node.ParentNode.InnerXml = $node.ParentNode.InnerXml.Replace($node.OuterXml, $node.OuterXml.Insert(0, "<!--").Insert($node.OuterXml.Length+4, "-->"))
$xml.Save("c:\test.xml")

test.xml

<root>
  <!--<abc key="test" value="samplevalue"></abc>-->
  <abc key="sa" value="dsad">sda
</abc>
</root>

非常感谢。它正在对节点进行注释。但我看到的一件事是,由于节点属于命名空间,Node.outXml包含在节点末尾附加的命名空间。但这不是预期的结果。有没有办法防止命名空间出现在Node.OuterXml中。 - user1595214
你的示例中没有包含任何命名空间。如果需要帮助,请提供一个有效的 XML 示例和你尝试过但不起作用的代码。 - Frode F.
我的XML如下: 我正在使用与您上面编写的完全相同的代码,但是在代码中调用node.Outerxml时,它会附加XML的命名空间。 - user1595214
XML文件中有多个名称空间吗?如果有,请提供一个包括根对象等有效示例。请通过更新你的问题来提供它,而不是在评论中提供。通过你提供的示例和 $node = $xml.selectSingleNode('//Connection')(获取连接标记而不是其他名称空间),它可以完美运行,这里没有额外的名称空间。 - Frode F.

6
这是一个用PowerShell编写的函数,用于“注释XML节点”:
function CommentXmlNode([String] $filePath, [String] $nodeXPath)
{
    [xml]$xml = Get-Content -Path "$filePath"

    # Find the nodes that we want to comment
    $xml.SelectNodes("$nodeXPath") | ForEach-Object {

        $nodeToComment = $_;
        $comment = $xml.CreateComment($nodeToComment.OuterXml);

        # Comment the node
        $nodeToComment.ParentNode.ReplaceChild($comment, $nodeToComment);
    }

    # Save the file
    $xml.Save("$filePath");
}

以下是一个 PowerShell 函数,用于取消注释 XML 节点:
function UncommentXmlNode([String] $filePath, [String] $searchCriteria)
{    
    [xml]$xml = Get-Content -Path "$filePath"

    # Find all comments on the xml file
    $xml.SelectNodes("//comment()") | ForEach-Object {     

        # We convert the comment to an xml
        $nodeToConvert = $_;  
        $convertedNode = $nodeToConvert.InnerText | convertto-xml 
        [xml]$xmlConvertedNode = $convertedNode

        # Find the comment that match our search criteria
        $xmlConvertedNode.SelectNodes("/descendant::*[contains(text(), '$searchCriteria')]") | ForEach-Object { 

            $nodeToUncomment = $_;

            $strToFind = "<!--" + $nodeToUncomment.InnerText + "-->"

            $strReplacement = $nodeToUncomment.InnerText

            # Replace the commented string with uncommented one
            $con = Get-Content "$filePath"
            $con | % { $_.Replace($strToFind, $strReplacement) } | Set-Content "$filePath"
        }
    }

}

你可以这样使用它们:
CommentXmlNode "D:\temp\file.xml" "YourXPath"

--

UncommentXmlNode "D:\temp\file.xml" "Some String in the xml node to Uncomment"

谢谢您。我想知道您是否找到了一种在保留格式的同时进行注释的方法。 - Blake Niemyjski

0

如果你想保留格式且不使用字符串替换,可以使用这段引用块。

它会建立一个临时节点,其中包含注释节点值,但不包括注释标签,然后进行替换处理。

# path to the file
$File = "c:\pathtoyourfile\example.xml"

# XPath to the element to un comment
$XPath = "/Settings/SettingNode[@name='Installation']/SettingNode[@name='Features']/Setting[@name='Features' and @scope='Installation']/StringArray/String"

# get xml file
$xmlFile = [xml](Get-Content $File) 

# get parent and child path from XPath
$parentXPath = $XPath.Substring(0, $XPath.LastIndexOf('/'))
$childXPath = $XPath -replace "$parentXPath/", ''

# get comment
$xmlNode = $xmlFile.SelectNodes("$parentXPath/comment()") | ? { $_.InnerText -match "<$childXPath" }

# create node containing comment content
$tempNode = $xmlFile.CreateElement("tempNode")          
$tempNode.InnerXml = $xmlNode.Value
$replaceNode = $tempNode.SelectSingleNode("/$childXPath")

# process replacement 
$xmlNode.ParentNode.ReplaceChild($replaceNode, $xmlNode)

# save change
$xmlFile.Save($File)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接