2016-05-12 1 views
-1

Заранее спасибо. У меня есть xmldocument неизвестной структуры и разнородных элементов. Я хочу, чтобы перебрать все элементы, получающих имя элемента и его значения в конечном итоге восстановить документ XML в ключи реестра и значенияИтерация через дерево xml с неизвестной структурой и размером (для xml в реестре)

пример

<Root> 
    <Names> 
    <Name>Bob</Name> 
    </Names> 
    <Locations> 
    <States> 
     <State>Ohio</State> 
     <State>Michigan</State> 
     <State> 
     Florida 
     <WeatherType>Hot</WeatherType> 
     </State> 
    </States> 
    </Locations> 
</Root> 

выход будет включать XPath (который я хотел бы использовать для reg path) для каждого значения элемента (которое я буду использовать для значения ключа reg). Результат будет выглядеть примерно так.

Root\Names\Name = Bob 
Root\Locations\States\State = Ohio 
Root\Locations\States\State = Michigan 
Root\Locations\States\State = Florida 
Root\Locations\States\State\Florida\WeatherType = Hot 

ответ

1

Вывод, который вы ищете, не является xpath. Ex. xpath для WeatherType -node - Root/Locations/States/State[contains(text(),'Florida')]/WeatherType.

Чтобы получить то, что вы просите, я бы подойти к нему так:

  1. Найти все узлы с текстовым значением
  2. Получить путь для родительских узлов
    • Добавить текст-значение к пути, когда существуют братья и сестры одного и того же типа (имя-элемента), например. Состояния.
  3. Выход path = text-value

Ex:

#$xml = [xml](Get-Content -Path myfile.xml) 
$xml = [xml]@" 
<Root> 
    <Names> 
    <Name>Bob</Name> 
    </Names> 
    <Locations> 
    <States> 
     <State>Ohio</State> 
     <State>Michigan</State> 
     <State> 
     Florida 
     <WeatherType>Hot</WeatherType> 
     </State> 
    </States> 
    </Locations> 
</Root> 
"@ 

#Get nodes with text-value 
$nodesWithText = $xml.SelectNodes("//*[text()]") 

foreach($node in $nodesWithText) { 
    #Start with end of path (element-name of the node with text-value) 
    $path = $node.LocalName 
    #Get parentnode 
    $parentnode = $node.ParentNode 

    #Loop until document-node (parent of root-node) 
    while($parentnode.LocalName -ne '#document') { 

     #If sibling with same LocalName (element-name) exists 
     if(@($parentnode.ParentNode.ChildNodes | Where-Object { $_.LocalName -eq $parentnode.LocalName }).Count -gt 1){ 
      #Add text-value to path 
      $path = "{0}\$path" -f ($parentnode.'#text').Trim() 
     } 

     #Add LocalName (element-name) for parent to path 
     $path = "$($parentnode.LocalName)\$path" 

     #Go to next parent node 
     $parentnode = $parentnode.ParentNode 
    } 

    #Output "path = text-value" 
    "$path = $(($node.'#text').Trim())" 
} 

Выход:

Root\Names\Name = Bob 
Root\Locations\States\State = Ohio 
Root\Locations\States\State = Michigan 
Root\Locations\States\State = Florida 
Root\Locations\States\State\Florida\WeatherType = Hot 
+0

Абсолютно блестящий. Чистый и простой. Я думал, что у меня должна быть функция, которая будет продолжать называть себя для каждого элемента, это даже лучше. Большое спасибо за то, что нашли время, чтобы ответить! –

+0

Добро пожаловать. Лично я бы обернул его в функцию для преобразования каждого узла в путь, чтобы он был повторно использован. Затем сохраните только «select text nodes» и foreach-loop в скрипте. Но это только мое личное предпочтение, поэтому я его не выпускал. Только 4 строки кода, чтобы изменить его в любом случае. :-) –

Смежные вопросы