Заменить имя атрибута в SQL Server XML

У меня есть таблица MyTable со столбцом xml MyXmlField следующим образом:

    <Root>
      <Node Type="type1" position="0"/>
      <Node Type="type2" position="2"/>
      <Node Type="type3" position="4"/>
      <Node Type="type4" position="2"/>
      <Node Type="type5" position="4"/>
      <Node Type="type6" position="0"/>
    </Root>

Атрибут Type имеет значение, которое может быть любым из следующих значений:

    type1, type2, type3, type4, type5, type6.

Атрибут position имеет значение, которое может быть любым целым числом.

Что я хотел бы сделать с XQuery, так это обновить атрибут Type каждого элемента Node следующим образом:

  • изменить имя с Type на Identifier

Итак, наконец, я хотел бы иметь это:

    <Root>
      <Node Identifier="type1" position="0"/>
      <Node Identifier="type2" position="2"/>
      <Node Identifier="type3" position="4"/>
      <Node Identifier="type4" position="2"/>
      <Node Identifier="type5" position="4"/>
      <Node Identifier="type6" position="0"/>
    </Root> 

Я новичок в XQuery, и я не вижу, как это сделать правильно, кроме как преобразовать все в varchar и выполнить замену. Прямо сейчас я могу запрашивать каждое значение только с помощью 6 жестко запрограммированных запросов, например:

    /Root/Node[@Type=type1)]/text())[1]

person user2443476    schedule 29.11.2017    source источник


Ответы (1)


Попробуйте следующий подход, но вам нужно учитывать возможные проблемы с производительностью:

with
  MyTable as(
    select cast(x as xml) MyXmlField
    from(values('
<Root>
  <Node Type="type1" position="0"/>
  <Node Type="type2" position="2"/>
  <Node Type="type3" position="4"/>
  <Node Type="type4" position="2"/>
  <Node Type="type5" position="4"/>
  <Node Type="type6" position="0"/>
</Root>
'),('
<Root id="170">
  <Node Type="type1" position="0"/>
  <Node Type="type2" position="2"/>
  <Node Type="type3" position="4"/>
  <Node Type="type4" position="2"/>
  <Node Type="type5" position="4"/>
  <Node Type="type6" position="0"/>
  <foo/>
  <foo bar="42">170</foo>
</Root>
'))t(x)
  )
select MyXmlField.query('
<Root>
  {/Root/@*}
  {
    for $elem in /Root/*
      return
        if(local-name($elem) = "Node")
        then
          <Node>
          {
            for $attr in $elem/@*
              return
                if(local-name($attr) = "Type")
                then attribute Identifier {$attr}
                else $attr
          }
          {$elem/node()}
          </Node>
        else $elem
  }
</Root>
')
from MyTable
person Andrei Odegov    schedule 29.11.2017