XML-фильтр Powershell

#xml #powershell #filtering

#xml #powershell #фильтрация

Вопрос:

Я пытаюсь удалить файлы в папке на основе любой папки, содержащей XML-файл с модальностью тега, содержащей anyType=»CT», но быстро столкнулся с проблемой при попытке фильтрации по содержимому XML

Я могу вернуть некоторый контент, но как только я пытаюсь выполнить любую фильтрацию или попытаться перейти к содержимому, я получаю пустой результат.

Это настолько глубоко, насколько я могу запрашивать и по-прежнему возвращать содержимое из XML-файла

 $xmlfile = get-Content .7.86.7.7053.61.159438.472144765.1719.XML
$xmlfile.ArrayOfPublicXMLElement.PublicXMLElement.ElementName
  

как только я пытаюсь углубиться, я не получаю никакого результата, например

 $xmlfile.ArrayOfPublicXMLElement.PublicXMLElement.Elementname |where {$_.name -eq "Modality"}
$xmlfile.ArrayOfPublicXMLElement.PublicXMLElement.Elementname |where {$_.name -eq "anyType"}
$xmlfile.ArrayOfPublicXMLElement.PublicXMLElement.Elementname |where {$_.name -eq "CT"}
$xmlfile.ArrayOfPublicXMLElement.PublicXMLElement | where {$_.name -eq "00080060"}
  

Вот копия XML, который я пытаюсь отфильтровать, я предполагаю, что это связано с форматом XML-файла, с которым у меня возникают большие трудности, или просто из-за неправильного понимания формата XML или того, как powershell взаимодействует с ним?

 <?xml version="1.0" encoding="utf-8"?>
<ArrayOfPublicXMLElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <PublicXMLElement>
    <ElementName>Acquisition Time</ElementName>
    <Tag>00080032</Tag>
    <VR>TM</VR>
    <ElementData>
      <anyType xsi:type="xsd:string">105343</anyType>
    </ElementData>
  </PublicXMLElement>    <ElementName>Accession Number</ElementName>
    <Tag>00080050</Tag>
    <VR>SH</VR>
    <ElementData>
      <anyType xsi:type="xsd:string" />
    </ElementData>
  </PublicXMLElement>
  <PublicXMLElement>
    <ElementName>Modality</ElementName>
    <Tag>00080060</Tag>
    <VR>CS</VR>
    <ElementData>
      <anyType xsi:type="xsd:string">CT</anyType>
    </ElementData>
  </PublicXMLElement>
  <PublicXMLElement>
    <ElementName>Station Name</ElementName>
    <Tag>00081010</Tag>
    <VR>SH</VR>
    <ElementData>
      <anyType xsi:type="xsd:string">M_Source</anyType>
    </ElementData>
  </PublicXMLElement>
  <PublicXMLElement>
    <ElementName>Rescale Slope</ElementName>
    <Tag>00281053</Tag>
    <VR>DS</VR>
    <ElementData>
      <anyType xsi:type="xsd:string">1.0</anyType>
    </ElementData>
  </PublicXMLElement>
</ArrayOfPublicXMLElement>
  

Комментарии:

1. Недопустимый XML-файл. У первого </PublicXMLElement> нет соответствующего начального тега.

2. Я бы предположил, что тогда я ничего не могу с этим поделать? Я не могу изменить XML.

3. Кто или что мешает вам получить действительный XML-файл? Если вы не можете его отредактировать, все, что у вас есть, это GIGO .

4. Я хотел бы извиниться, я обрезал документ, поскольку полный XML-файл имеет около 1635. Я обрезал 1 строку слишком много!!!!

Ответ №1:

Если у вас есть только недопустимый XML, и, если я правильно понимаю, вы хотите удалить все эти файлы, где:

  • существует тег <ElementName>Modality</ElementName>
  • у которого есть тег <ElementData> ,
  • который, в свою очередь, имеет тег <anyType> , содержащий значение CT

тогда вам придется прибегнуть к использованию регулярных выражений.

 $regex = '(?s)<ElementName>Modality</ElementName>.*<ElementData>s*<anyType[^>]*>CT</anyType>'
Get-ChildItem -Path 'D:Test' -Filter '*.xml' -File -Recurse | ForEach-Object {
    $content = Get-Content -Path $_.FullName -Raw
    if ($content -match $regex) {
        $_ | Remove-Item -Force -WhatIf  # see below
    }
}
  

Снимите -WhatIf переключатель, если вы уверены, что код удалит правильные файлы, чтобы фактически удалить их.

Сведения о регулярных выражениях

 (?s)                                    Dot matches line breaks
<ElementName>Modality</ElementName>     Match the character string “<ElementName>Modality</ElementName>” literally
.                                       Match any single character
   *                                    Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
<ElementData>                           Match the character string “<ElementData>” literally
s                                      Match a single character that is a “whitespace character” (any Unicode separator, tab, line feed, carriage return, vertical tab, form feed, next line)
   *                                    Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
<anyType                                Match the character string “<anyTypeliterally
[^>]                                    Match any character that is NOT a “>”
   *                                    Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
>CT</anyType>                           Match the character string “>CT</anyType>” literally
  

Ответ №2:

Это работает так, как вам нравится?

 $xmlfile.ArrayOfPublicXMLElement.PublicXMLElement | Where-Object { ($_.ElementName -like "Modality") -and ($_.ElementData.anyType.InnerText -like "CT")}
  

Это простой способ получить количество совпадений:

 (@($xmlfile.ArrayOfPublicXMLElement.PublicXMLElement | Where-Object { ($_.ElementName -like "Modality") -and ($_.ElementData.anyType.InnerText -like "CT")})).Count
  

Комментарии:

1. Привет, извиняюсь, что не ответил раньше, именно так я представлял себе, как это работает в powershell, но по какой-то причине я получаю пустой результат каждый раз, когда пытаюсь использовать этот метод запроса XML-файла. Приведенный выше ответ от Тео работает для меня, но я хотел бы поблагодарить вас за время, потраченное на ответ на мой вопрос, и мои извинения за то, что я не могу заставить его работать. Количество соответствует 0)

2. И упорство имеет значение!! оказывается, я был довольно глуп, пропустив [xml], как только я добавил, что он смог вернуть желаемые результаты!!!! СПАСИБО, У меня также не может быть 2 ответов, хотя оба решают мою проблему!!