XML-манипуляции Powershell: сохраняйте только узлы с максимальной датой - PullRequest
0 голосов
/ 27 марта 2019

У меня есть XML-файл со следующей (упрощенной) структурой:

<XML>
    <Observation>
       <Dimension value="2018-11-01" />
       <Value value="123" />
    </Observation>
    <Observation>
       <Dimension value="2018-11-02" />
       <Value value="456" />
    </Observation>
    <Observation>
       <Dimension value="2018-12-01" />
       <Value value="789" />
    </Observation>
    <Observation>
       <Dimension value="2018-12-02" />
       <Value value="222" />
    </Observation>
</XML>

Задача состоит в том, чтобы удалить узлы, где дата в атрибуте value узла Dimension не максимальная дата. Или другими словами: должны быть сохранены только узлы, содержащие максимальную / максимальную дату в атрибуте value узла Dimension. Это должно быть сделано в месяц .

Следовательно, результат должен выглядеть следующим образом:

<XML>
    <Observation>
       <Dimension value="2018-11-02" />
       <Value value="456" />
    </Observation>
    <Observation>
       <Dimension value="2018-12-02" />
       <Value value="222" />
    </Observation>
</XML>

Как это можно сделать в Powershell? Я знаю, как читать XML-файл и как делать запросы на основе XPath:

$doc.SelectNodes("//Observation", $ns)

Однако я не знаю, как а) определить максимальную / максимальную дату в месяце и б) как удалить узлы, которые не содержат максимальную / максимальную дату.

EDIT:

Другой, возможно, более простой способ сделать это будет следующим:

  1. найти максимальные / максимальные даты в месяц
  2. хранить только те узлы, которые иметь эту дату.

Ответы [ 2 ]

1 голос
/ 27 марта 2019

Группировка по месяцам с использованием Group-Object упрощает процесс.

$doc.XML.Observation | Group-Object { $_.Dimension.value.Substring(0,7) } | foreach {
    $_.Group | Sort-Object { $_.Dimension.value } -Descending |
    Select-Object -Skip 1 | foreach { $doc.XML.RemoveChild($_) }
}

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

$doc.SelectNodes("//message:DataSet/generic:Series", $ns) | foreach {
    $_.SelectNodes("./generic:Obs", $ns) | Group-Object { $_.ObsDimension.value.Substring(0,7) } | foreach {
        $_.Group | Sort-Object { $_.ObsDimension.value } -Descending |
        Select-Object -Skip 1 | foreach { $_.ParentNode.RemoveChild($_) }
    }
}
0 голосов
/ 27 марта 2019

Это должно делать именно то, что вы хотите:

Add-Type -AssemblyName System.Collections

$filePath   = "inputfile.xml"
$filePath1  = "outputfile.xml"

$xmlContent = New-Object System.Xml.XmlDocument
$xmlContent.PreserveWhitespace = $true
$xmlContent = [xml]([System.IO.File]::ReadLines($filePath))

[System.Collections.Generic.List[string]]$highestValues = @()

$oldMonth = ""
$oldYear  = ""

$xmlContent.XML.Observation.Dimension | Sort-Object { $_.value }  -Descending | ForEach-Object {

    $currentDate  = $_.value
    $currentYear  = $currentDate.Substring(0,4)
    $currentMonth = $currentDate.Substring(5,2)

    if( $currentYear -ne $oldYear -or $currentMonth -ne $oldMonth ) {
        $oldYear  = $currentYear
        $oldMonth = $currentMonth
        $highestValues.Add( $currentDate )
    }
}

$numItems   = ($xmlContent.XML.Observation.Dimension).Count

for( $i = $numItems - 1; $i -ge 0; $i-- ) {

    if( !$highestValues.Contains( $xmlContent.XML.Observation.Dimension[$i].value ) ) {
        [void]$xmlContent.XML.RemoveChild( $xmlContent.XML.Observation[$i] )
    }

}

[void]$xmlContent.Save( $filePath1 )
...