【问题标题】:how to query all the children nodes for particular attribute如何查询所有子节点的特定属性
【发布时间】:2016-08-29 16:36:34
【问题描述】:

我有以下几种 xml 结构:

<ObjectTemplate>
 <Sections>
   <Section Name="something" Identifier="something">
     <Options>
       <Choice text="something">
         <TextField visibility="private">

但并不总是像上面那样。它可以是 Section 下的直接字段:

<ObjectTemplate>
     <Sections>
       <Section Name="something" Identifier="something">
          <TextField visiblity="private">

有没有办法让我查询节点的所有子节点的属性“可见性”?

到目前为止,我有以下工作代码只是为了从 xml 中提取部分:

select distinct identifier from (
select 
T.C.value('@Name', 'nvarchar(max)') as name,
T.C.value('@Identifier', 'nvarchar(50)') as identifier

from @templatexml tx
cross apply tx.CurrentTemplateXml.nodes('(ObjectTemplate/Sections/Section)') as T(C)
) as temp

【问题讨论】:

  • 嗨,这个问题解决了吗?您需要进一步的帮助吗?

标签: sql sql-server xml tsql


【解决方案1】:

如果您不太关心 /TextField 节点的确切位置,这里有一个非常简单的解决方案:

declare @t table(
    Id int identity(1,1) primary key,
    XMLData xml not null
);

insert into @t (XMLData)
values
('<ObjectTemplate>
  <Sections>
    <Section Name="something1" Identifier="ident1">
      <Options>
        <Choice text="something">
          <TextField visibility="private" />
        </Choice>
      </Options>
    </Section>
  </Sections>
</ObjectTemplate>')
,('<ObjectTemplate>
  <Sections>
    <Section Name="something2" Identifier="ident2">
      <TextField visibility="public" />
      <TextField visibility="friend" />
    </Section>
  </Sections>
</ObjectTemplate>');

select t.Id,
    s.c.query('.') as [TextField],
    s.c.value('./@visibility', 'varchar(100)') as [Visibility]
from @t t
    cross apply t.XMLData.nodes('//TextField[@visibility]') s(c);

【讨论】:

  • 我会以此查询节点的所有子节点以获取属性“可见性” 作为提示,OP 正在搜索 @visibility 而不是 @987654324 @。除了如果你只使用//*,如果使用更大的结构,这可能会变得很慢,我怀疑没有上下文的可见性标志是否有帮助......
【解决方案2】:

我不完全明白你想要什么,但你可以试试这样:

DECLARE @tbl TABLE(ID INT IDENTITY,xmlColumn XML);
INSERT INTO @tbl VALUES
('<ObjectTemplate>
  <Sections>
    <Section Name="something1" Identifier="ident1">
      <Options>
        <Choice text="something">
          <TextField visibility="private" />
        </Choice>
      </Options>
    </Section>
  </Sections>
</ObjectTemplate>')
,('<ObjectTemplate>
  <Sections>
    <Section Name="something2" Identifier="ident2">
      <TextField visibility="private" />
    </Section>
  </Sections>
</ObjectTemplate>');

SELECT tbl.ID
      ,Sec.value('@Name','varchar(max)') AS SectionName
      ,Sec.value('@Identifier','varchar(max)') AS SectionIdentifier
      ,att.value('local-name(../..)','varchar(max)') AS ParentParentNode
      ,att.value('local-name(..)','varchar(max)') AS ParentNode
      ,att.value('local-name(.)','nvarchar(max)') AS AttributeName
      ,att.value('.','nvarchar(max)') AS AttributValue
FROM @tbl AS tbl
CROSS APPLY tbl.xmlColumn.nodes('/ObjectTemplate/Sections/Section') AS A(Sec)
CROSS APPLY Sec.nodes('//*') AS B(Nd)
CROSS APPLY Nd.nodes('attribute::*[local-name()="visibility"]') AS C(att)

结果

1   something1  ident1  Choice  TextField   visibility  private
2   something2  ident2  Section TextField   visibility  private

【讨论】:

    【解决方案3】:

    您还可以cross apply 更深层次。像这样的。

    select distinct identifier from (
    select 
    T.C.value('@Name', 'nvarchar(max)') as name,
    T.C.value('@Identifier', 'nvarchar(50)') as identifier,
    V.x.value('@visibility', 'nvarchar(50)') as visibility
    
    from @templatexml tx
    cross apply tx.CurrentTemplateXml.nodes('(ObjectTemplate/Sections/Section)') as T(C)
    cross apply T.C.nodes('//*[@visibility]') as V(x) -- Correction thnx @Shnugo
    ) as temp
    

    【讨论】:

    • 如果你想更深入,你必须使用CROSS APPLY T.C.nodes(...),而不是再次从根目录下使用CROSS APPLYCROSS APPLY 适用于 current-row-base ...
    猜你喜欢
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    • 2011-01-30
    • 2012-12-23
    • 2019-11-14
    • 2017-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多