#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 “<anyType” literally
[^>] 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 ответов, хотя оба решают мою проблему!!