1

すべてのデータを xml から SQL Server の文字列に取得しようとしています。

したがって、次のような xml があるとします。

<node1>
  <node2>
    <node3 att1="1">
      456
    </node3>
    <node4 att2="25"/>
  </node2>
</node1>

私が欲しいのは、次のようなデータを取得することです:

╔══════════════════════════╦════════════╗
║                     Name ║      Value ║
╠══════════════════════════╬════════════╣
║ node1/node2/node3        ║        456 ║
║ node1/node2/node3/@att1  ║          1 ║
║ node1/node2/node3/@att2  ║         25 ║
╚══════════════════════════╩════════════╝

XPath はよく覚えていませんが、再帰クエリ ( SQL FIDDLE )で実行できます。

declare @data xml

set @data = '<root><node2><node3 att1="1">ggf</node3><node4 att2="25"/></node2></root>'

;with
CTE_xpath as (
  select
    T.C.value('local-name(.)', 'nvarchar(max)') as Name,
    T.C.query('./*') as elements,
    T.C.value('text()[1]', 'nvarchar(max)') as Value
  from @data.nodes('*') as T(c)

  union all

  select
    p.Name + '/' + T.C.value('local-name(.)', 'nvarchar(max)') as Name,
    T.C.query('./*') as elements,
    T.C.value('text()[1]', 'nvarchar(max)') as Value
  from CTE_xpath as p
    cross apply p.elements.nodes('*') as T(C)
  union all

  select
    p.Name + '/' +
    T.C.value('local-name(..)', 'nvarchar(max)') + '/@' +
    T.C.value('local-name(.)', 'nvarchar(max)') as Name,
    null as elements,
    T.C.value('.', 'nvarchar(max)') as Value
  from CTE_xpath as p
    cross apply p.elements.nodes('*/@*') as T(C)
)
select Name, Value
from CTE_xpath
where Value is not null

このタスクを実行する最善の方法は何だと思いますか?

4

1 に答える 1

2

Tony Hopkinson のコメントよりもかなり簡潔な解決策を次に示します。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <items>
      <xsl:apply-templates 
             select="(//* | //@*)[text()[normalize-space()] or
                                  not(self::*) and normalize-space()]" />
    </items>
  </xsl:template>

  <xsl:template match="@* | node()">
    <item value="{normalize-space()}">
      <xsl:attribute name="path">
        <xsl:apply-templates select="ancestor-or-self::node()[parent::node()]" 
                             mode="path" />
      </xsl:attribute>
    </item>
  </xsl:template>

  <xsl:template match="@* | node()" mode="path">
    <xsl:value-of select="concat('/',
                                 substring('@', 1, not(self::*)),
                                 name())"/>
  </xsl:template>
</xsl:stylesheet>

サンプル入力で実行した結果は次のとおりです。

<items>
  <item value="456" path="/node1/node2/node3" />
  <item value="1" path="/node1/node2/node3/@att1" />
  <item value="25" path="/node1/node2/node4/@att2" />
</items>

より簡潔で直感的な

<xsl:apply-templates select="//*[text()[normalize-space()]] |
                             //@*[normalize-space()]" />

しかし、何らかの理由でこれにより IDE 全体がクラッシュし、その理由がわかりません。

于 2013-06-29T14:29:48.790 に答える