Получить отдельный список узлов XML из большого файла - PullRequest
0 голосов
/ 21 декабря 2018

Я пытаюсь получить отдельный список имен узлов из файла XML.Я добился успеха с рекурсивным CTE, похожим на https://stackoverflow.com/a/2274091/1735928,, но только с моими файлами размером менее 1 миллиона символов.Кроме того, запрос никогда не возвращается.Некоторые из моих файлов имеют длину около 100 м символов.

С тех пор я перешел к использованию PowerShell.Для этого образца XML:

<?xml version="1.0" encoding="UTF_8"?>
<root>
  <childA>
    <descendant1>
      <descendant1_1>
        <descendant1_1_1>1111111111</descendant1_1_1>
      </descendant1_1>
    </descendant1>
    <descendant2>0</descendant2>
  </childA>
  <childA>
    <descendant1>
      <descendant1_1>
        <descendant1_1_1>2222222222</descendant1_1_1>
      </descendant1_1>
    </descendant1>
    <descendant2>2</descendant2>
  </childA>
  <childB>
    <descendant1>
      <descendant1_1>
        <descendant1_1_1>2222222222</descendant1_1_1>
      </descendant1_1>
    </descendant1>
    <descendant3>0</descendant3>
  </childB>
  <childC>
    <descendant4>0</descendant4>
  </childC>
  <childC>
    <descendant4>6</descendant4>
  </childC>
</root>

Я получил:

$xml.childnodes[1].childnodes | select -uniq | foreach { $xml.childnodes[1].($_.name).childnodes.name | select -uniq }

, что дает мне:

descendant1
descendant2
descendant1
descendant3
descendant4

, но это не включаетдальнейшие потомки.В конечном итоге я пытаюсь вернуть таблицу в SQL, которая выглядит следующим образом:

root | childA | descendant1
root | childA | descendant1_1
root | childA | descendant1_1_1
root | childA | descendant2
root | childB | descendant1
root | childB | descendant1_1
root | childB | descendant1_1_1
root | childB | descendant3
root | childC | descendant4

Ответы [ 2 ]

0 голосов
/ 22 декабря 2018

Если мы говорим о жестко закодированных решениях этой проблемы, то вот мое решение с использованием SQL Server.

DECLARE @x XML = '
<root>
  <childA>
    <descendant1>
      <descendant1_1>
        <descendant1_1_1>1111111111</descendant1_1_1>
      </descendant1_1>
    </descendant1>
    <descendant2>0</descendant2>
  </childA>
  <childA>
    <descendant1>
      <descendant1_1>
        <descendant1_1_1>2222222222</descendant1_1_1>
      </descendant1_1>
    </descendant1>
    <descendant2>2</descendant2>
  </childA>
  <childB>
    <descendant1>
      <descendant1_1>
        <descendant1_1_1>2222222222</descendant1_1_1>
      </descendant1_1>
    </descendant1>
    <descendant3>0</descendant3>
  </childB>
  <childC>
    <descendant4>0</descendant4>
  </childC>
  <childC>
    <descendant4>6</descendant4>
  </childC>
</root>
';

SELECT
  x.n.value('fn:local-name(.)', 'NVARCHAR(MAX)') root,
  L2.n.value('fn:local-name(.)', 'NVARCHAR(MAX)') L2,
  L3.n.value('fn:local-name(.)', 'NVARCHAR(MAX)') L3,
  L4.n.value('fn:local-name(.)', 'NVARCHAR(MAX)') L4,
  L5.n.value('fn:local-name(.)', 'NVARCHAR(MAX)') L5
FROM @x.nodes('/*') x(n)
OUTER APPLY x.n.nodes('*') L2(n)
OUTER APPLY L2.n.nodes('*') L3(n)
OUTER APPLY L3.n.nodes('*') L4(n)
OUTER APPLY L4.n.nodes('*') L5(n);

Вывод

+------+--------+-------------+---------------+-----------------+
| root |   L2   |     L3      |      L4       |       L5        |
+------+--------+-------------+---------------+-----------------+
| root | childA | descendant1 | descendant1_1 | descendant1_1_1 |
| root | childA | descendant2 |               |                 |
| root | childA | descendant1 | descendant1_1 | descendant1_1_1 |
| root | childA | descendant2 |               |                 |
| root | childB | descendant1 | descendant1_1 | descendant1_1_1 |
| root | childB | descendant3 |               |                 |
| root | childC | descendant4 |               |                 |
| root | childC | descendant4 |               |                 |
+------+--------+-------------+---------------+-----------------+
0 голосов
/ 22 декабря 2018

Ниже приведено наивное решение, предполагающее, что вы знаете глубину своего xml.Но, вероятно, вы можете сделать все это с помощью xqury и, таким образом, сделать это на стороне SQL

[xml]$x = "your xml here"

# ------ LEVEL 2 children

$L2 = $x | Select-Xml "//root/*/*"

foreach($n in $L2) { 
 $L1 = $n.node.ParentNode.LocalName
 $CHILD = $n.node.localname
 [PSCustomObject]@{L1=$L1; CHILD = $CHILD}
}

# ------ LEVEL 3 children 


$L3 = $x | Select-Xml "//root/*/*/*"

foreach($n in $L3) { 
 $L1 = $n.node.ParentNode.ParentNode.LocalName
 $CHILD = $n.node.localname
 [PSCustomObject]@{L1=$L1; CHILD = $CHILD}
}

# ------ LEVEL 4 children 


$L4 = $x | Select-Xml "//root/*/*/*/*"

foreach($n in $L4) { 
 $L1 = $n.node.ParentNode.ParentNode.ParentNode.LocalName
 $CHILD = $n.node.localname
 [PSCustomObject]@{L1=$L1; CHILD = $CHILD}

}

Также добавив версию sql xquery.Он все еще требует знания структуры и делает только один уровень за один раз, но он не имеет перекрестного применения / объединения, поэтому, вероятно, будет лучше работать с большими файлами

select
 T.c.query('local-name(.)') as self
 ,T.c.query('local-name(..)') as parent
 ,T.c.query('local-name(../..)') as Gparent
  ,T.c.query('local-name(../../..)') as GGparent
from @x.nodes('/root/*/*/*/*') T(c)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...