【问题标题】:How to dynamically filter out XML nodes using PowerShell?如何使用 PowerShell 动态过滤 XML 节点?
【发布时间】:2011-09-22 08:43:40
【问题描述】:

非常感谢您对以下问题的任何帮助:

我正在使用 PowerShell 处理大量 XML 数据。 XML 存储在 .txt 文件中,我的 PowerShell 脚本在读取文件后将内容写入数据库。

如果某些 XML 节点没有正确的“signatureNumber”,我想过滤掉它们(通过长度验证,或者最好使用正则表达式验证)。

下面是 XML 结构:

<Objs xmlns="http://schemas.microsoft.com/powershell/2004/04" Version="1.1.0.1">
  <Obj RefId="0">
    <TN RefId="0">
      <T>WebServiceProxy.TestOutputElement</T>
      <T>System.Object</T>
    </TN>
    <ToString>WebServiceProxy.TestOutputElement</ToString>
    <Props>
      <DT N="declarationDate">2011-08-29T10:28:17</DT>
      <B N="declarationDateSpecified">true</B>
      <Nil N="testDate" />
      <B N="testDateSpecified">true</B>
      <S N="XMLdocument">&lt;?xml S>
      <I32 N="id">1359569</I32>
      <B N="idSpecified">true</B>
      <I32 N="decisionCode">5</I32>
      <B N="decisionCodeSpecified">true</B>
      <S N="documentStatus">issued</S>
      <S N="incidentSignature">Nc-e 491993/11</S>
      <S N="signatureNumber">11111111111/222222/33</S> <----- signature length (21) is OK! We want the whole <Obj> 
    </Props>
  </Obj>
  <Obj RefId="1">
    <TNRef RefId="0" />
    <ToString>WebServiceProxy.TestOutputElement</ToString>
    <Props>
      <DT N="declarationDate">2011-08-29T10:28:18</DT>
      <B N="declarationDateSpecified">true</B>
      <Nil N="testDate" />
      <B N="testDateSpecified">true</B>
      <S N="XMLdocument">&lt;?xml D__x000A_</S>
      <I32 N="id">1359570</I32>
      <B N="idSpecified">true</B>
      <I32 N="decisionCode">5</I32>
      <B N="decisionCodeSpecified">true</B>
      <S N="documentStatus">issued</S>
      <S N="incidentSignature">Nc-e 491923/11</S>
      <S N="signatureNumber">test</S> <----- wrong signature! <Obj> should be filtered out!
    </Props>
  </Obj>

使用类似代码循环读取内容:

$filedata = Get-Content ("C:\EXPORT\MyData"+$pageNumber+".txt")

读取每个文件后,XML 被写入数据库:

$Command.CommandText = "INSERT INTO dbo.ImportXml (MethodName,XmlData) VALUES ('"+$methodName+"','"+ $filedata+ "')"
$Command.ExecuteNonQuery() >> $log_message

目标是从$filedata 变量中过滤掉所有&lt;Obj&gt; 元素,如果它们包含长度不同于21 的“signatureNumber”。一切都必须在INSERT 之前完成。

我非常感谢任何建议!

更新:只是为了澄清一切。在我的示例中,&lt;Obj RefId="0"&gt; 可以,应该插入,&lt;Obj RefId="1"&gt; 应该从 XML 中完全删除。

【问题讨论】:

    标签: xml xpath powershell xquery powershell-2.0


    【解决方案1】:

    由于您将 XML 加载到数据库中,我认为您将不得不求助于一些丑陋的正则表达式:

    $filedata = [System.IO.File]::ReadAllText("C:\EXPORT\MyData"+$pageNumber+".txt")
    $re=[regex] '(?s)<Obj.*?<S N="signatureNumber">(.*?)</S>.*?</Obj>'
    $m = $re.Matches($filedata)
    $m | ?{ $_.Groups[1].value.length -ne 21} | %{ $filedata = $filedata.Replace($_.value,"")   }
    
    $filedata
    

    如果您在 Powershell 中使用 XML,我会建议如下:

    $fileXml = [xml]$filedata
    
    $filedata = foreach ($obj in $fileXml.Objs.Obj){
        $obj.Props.S | ?{ $_.N -eq "signatureNumber"} | %{if( $_."#text".length -eq 21) {$obj}}
    
    }
    
    $filedata
    

    【讨论】:

    • @mission - 抱歉,我使用了 [System.IO.File]::ReadAllText 并没有提及。更新了我的答案。
    猜你喜欢
    • 2012-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-15
    • 2020-05-15
    相关资源
    最近更新 更多