Как динамически отфильтровывать узлы XML с помощью PowerShell? - PullRequest
0 голосов
/ 21 сентября 2011

Буду очень признателен за любую помощь, которую вы можете получить, в отношении следующей проблемы:

Я обрабатываю большие объемы данных XML с помощью PowerShell.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

Цель состоит в том, чтобы отфильтровать все <Obj> элементы из переменной $filedata, если они содержат "signatureNumber" с длинойотличается от 21. Все должно быть сделано до ВСТАВКИ.

Буду очень признателен за любой совет!

ОБНОВЛЕНИЕ : Просто чтобы все прояснить.В моем примере <Obj RefId="0"> в порядке и должно быть вставлено, а <Obj RefId="1"> должно быть полностью удалено из XML.

1 Ответ

0 голосов
/ 21 сентября 2011

Поскольку вы загружаете 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

Если бы вы использовали XML в Powershell, я бы предложил что-то вроде этого:

$fileXml = [xml]$filedata

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

}

$filedata
...