【问题标题】:Not able to loop XML using Xpath using Powershell无法使用 Powershell 使用 Xpath 循环 XML
【发布时间】:2020-03-20 00:28:12
【问题描述】:

无法理解为什么我的简单 xpath 不适用于以下 XML。

我需要找到节点“部署”并删除子节点,然后添加一个新的子节点。应该很容易,但是不,XML 中有一些东西使我的代码无法通过简单地按名称选择部署节点来找到它。

XML(Clickonce .Net XML)

<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
  <assemblyIdentity name="PublishDev.app" version="3.1.0.182" publicKeyToken="38f29cb66cf790f2" language="neutral" processorArchitecture="x86" xmlns="urn:schemas-microsoft-com:asm.v1" />
  <description asmv2:publisher="KLP" asmv2:product="PublishDev" xmlns="urn:schemas-microsoft-com:asm.v1" />
  <deployment install="true">
    <subscription>
      <update>
        <expiration maximumAge="0" unit="days" />
      </update>
    </subscription>
    <deploymentProvider codebase="http://nrs.dev/NrsClient/PublishDev.application" />
  </deployment>
  <compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2">
    <framework targetVersion="4.7" profile="Client" supportedRuntime="4.0.30319" />
    <framework targetVersion="4.7" profile="Full" supportedRuntime="4.0.30319" />
  </compatibleFrameworks>
  <dependency>
    <dependentAssembly dependencyType="install" codebase="ApplicationFiles\PublishDev_3_1_0_182\PublishDev.exe.manifest" size="48466">
      <assemblyIdentity name="PublishDev.exe" version="3.1.0.182" publicKeyToken="38f29cb66cf790f2" language="neutral" processorArchitecture="x86" type="win32" />
      <hash>
        <dsig:Transforms>
          <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
        </dsig:Transforms>
        <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
        <dsig:DigestValue>zbbwOLiL12PznwEX7G3FGhmU8R0=</dsig:DigestValue>
      </hash>
    </dependentAssembly>
  </dependency>
</asmv1:assembly>

然后使用 Powershell 循环 XML

function loopXml{
    param(
        $nodes
    )
    write-host "*************************  Loop my xml********************* "
    foreach ($node in $nodes) {
        Write-host $node.toString()
    }
}

$deployManifestFullPath = "D:\temp\stripped.xml"

$sourcexml = [xml](get-content $deployManifestFullPath);
$nodes = $sourcexml.SelectNodes("deployment")
loopXml $nodes 

$nodes = $sourcexml.SelectNodes("//*", $ns)
loopXml $nodes 

输出

*************************  Loop my xml*********************
*************************  Loop my xml*********************
assembly
assemblyIdentity
description
deployment
subscription
update
expiration
deploymentProvider
compatibleFrameworks
framework
framework
dependency
dependentAssembly
assemblyIdentity
hash
Transforms
Transform
DigestMethod
DigestValue

我不明白为什么行

$nodes = $sourcexml.SelectNodes("deployment")

不返回部署节点。当我选择整个文档时,它就在那里,但是......好吧,需要一些帮助来弄清楚这个。

参考。 w3schools XPath Syntax 只需添加节点名称即可选择具有该名称的所有节点。在我的例子中,单个节点名为部署。

【问题讨论】:

    标签: xml powershell


    【解决方案1】:

    尝试改变

    $nodes = $sourcexml.SelectNodes("deployment")
    

    $nodes = $sourcexml.SelectNodes("//*[name()='deployment']")
    

    【讨论】:

    • 谢谢,成功了... 很困惑,因为 W3CSchools 说这项工作: nodename 选择名称为“nodename”的所有节点但是 - 不会花太多时间在上面,再次感谢!
    【解决方案2】:

    InvalidArgument:无法将值“System.Object[]”转换为类型“System.Xml.XmlDocument”。错误:“文件意外结束。以下元素未关闭:asmv1:assembly。第 40 行,位置 14。”

    你在 xml 的底部缺少这样的东西:

    </asmv1:assembly>
    

    如果您正确缩进$sourcexml.save('stripped.xml'),您会看到部署不是顶级节点。还有命名空间问题。

    您可以通过这种方式获取$nodes。只有一个。我不知道命名空间:

    $nodes = $sourcexml.assembly.deployment
    $nodes 
    
    
    install subscription deploymentProvider
    ------- ------------ ------------------
    true    subscription deploymentProvider
    

    嗯,这行得通:

    select-xml asmv1:assembly stripped.xml -Namespace @{asmv1='urn:schemas-microsoft-com:asm.v1'}
    
    
    Node     Path                           Pattern
    ----     ----                           -------
    assembly /Users/js/foo/stripped.xml     asmv1:assembly
    

    但不是这个:

    select-xml '//deployment' stripped.xml -Namespace @{asmv1='urn:schemas-microsoft-com:asm.v1'} 
    

    呃。这行得通。 x 可以是任何东西。不能是xmlns

    select-xml '//x:deployment' stripped.xml -Namespace @{x='urn:schemas-microsoft-com:asm.v2'}  
    
    
    Node       Path                           Pattern
    ----       ----                           -------
    deployment /Users/js/foo/stripped.xml     //x:deployment
    

    最后是带有命名空间的 selectnodes() 版本。您需要// 来搜索子节点,因为部署不是顶级节点。拥有命名空间会使事情变得更加棘手。 x 代表这里的默认命名空间。

    [System.Xml.XmlNamespaceManager]$nsmgr = $sourcexml.NameTable
    $nsmgr.AddNamespace('x','urn:schemas-microsoft-com:asm.v2')
    $nodes = $sourcexml.selectnodes('//x:deployment', $nsmgr)
    $nodes
    
    
    install subscription deploymentProvider
    ------- ------------ ------------------
    true    subscription deploymentProvider
    

    【讨论】:

    • 抱歉,这只是一个简单的编辑问题 - 结束标签的缩进不够,因此没有显示。已经更新了代码,所以现在应该没问题了。
    • 但是 - 是的部署不是顶级节点,但如果我没有完全弄错的话, $nodes = $sourcexml.SelectNodes("deployment") 是有效的 xpath。它应该在文档中的任何位置找到任何名为部署的节点。
    • 应该是$sourcexml.SelectNodes("//deployment")。但也有一个命名空间。
    猜你喜欢
    • 1970-01-01
    • 2012-04-07
    • 2011-12-25
    • 2014-02-28
    • 2014-05-29
    • 1970-01-01
    • 2011-09-23
    • 1970-01-01
    • 2021-07-21
    相关资源
    最近更新 更多