TSQL xQuery 如何获取 root/document 节点

TSQL xQuery how to I get the root/document node

我有一个 XML 字段,其中包含类似于 .Net 在表单中构建控件的方式的数据。假设您有一个 windows 表单,您可以向表单添加多个控件,它们显示在 .Controls 属性 下。一些控件本身也可以有面板,分组框等控件。类似于下面xml中显示的内容。

<Form>
<Name>MyForm</Name>
<TabCtrl>
    <Name>Tab1</Name>
    <Controls>
        <TextboxCtrl>
            <Name>MyTextBox</Name>
            <Location>3,10</Location>
            <Tag>34</Tag>
        </TextboxCtrl>
        <Label>
            <Name>MyLabel</Name>
            <Location>23,3</Location>
            <Tag>19</Tag>>
        </Label>
        <Panel>
            <Name>myPanel</Name>
            <Controls>
                <TextboxCtrl>
                    <Name>MyTextBox2</Name>
                    <Location>36,210</Location>
                    <Tag>34</Tag>
                </TextboxCtrl>
            </Controls>
        </Panel>
    </Controls>
</TabCtrl>
<TabCtrl>
    <Name>Tab2</Name>
    <Controls>
        ...
    </Controls>
</TabCtrl>

DB table 中有数千行,每行 xml 本身有时由 1000 个“控件”组成。当 TabCtrl 包含标签为 34 的控件时,我正在寻找一种查询 TabCtrl/Name 节点的方法。 我可以使用 xPath

通过此查询限制行
Select theXML from ViewTable where theXML.exist('//Tag[.="34"]') = 1

此外,我可以获得控件的名称而不是整个 xml:

Select theXML.query('//*[Tag="34"]/Label/text()') as 'Control Name'from ViewTable where theXML.exist('//Tag[.="34"]') = 1

如何获得 TabCtrl/Name?包含匹配 Tag 的元素的路径可以通过 1-n 级的 Controls 节点,因此使用 Xpath 语句将不起作用。 TabCtrl 将始终是 Form 节点的直接子节点

此查询将 return TabCtrl/Name 具有 Controls 节点的任何 TabCtrl 的 Grand child Tag =s 34:

DECLARE @theXML XML = '<Form>
<Name>MyForm</Name>
<TabCtrl>
    <Name>Tab1</Name>
    <Controls>
        <TextboxCtrl>
            <Name>MyTextBox</Name>
            <Location>3,10</Location>
            <Tag>34</Tag>
        </TextboxCtrl>
        <Label>
            <Name>MyLabel</Name>
            <Location>23,3</Location>
            <Tag>19</Tag>>
        </Label>
        <Panel>
            <Name>myPanel</Name>
            <Controls>
                <TextboxCtrl>
                    <Name>MyTextBox2</Name>
                    <Location>36,210</Location>
                    <Tag>34</Tag>
                </TextboxCtrl>
            </Controls>
        </Panel>
    </Controls>
</TabCtrl>
<TabCtrl>
    <Name>Tab2</Name>
    <Controls>
        ...
    </Controls>
</TabCtrl>
</Form>'


Select @theXML.query('//TabCtrl/Controls/*[Tag="34"]/../../Name') as 'Control Name'

输出:

<Name>Tab1</Name>

我不能 100% 确定这就是您要查找的内容,但这可能是您要在此处遵循的一般模式,如果您需要获得更深层嵌套的 Tag=34 节点,则可以使用附加查询。

可能的解决方案:

TabCtrl/Name 获取文本的一种可能方法,其中包含一个标签为 34 的控件:

Select theXML.query('//TabCtrl[Controls/*/Tag="34"]/Name/text()') as 'Control Name'

或者,如果您需要从它的后代开始到达 <TabCtrl>,那么您总是可以使用 parent::element_nameancestor::element_name.. 爬上树:

Select theXML.query('//*[Tag="34"]/ancestor::TabCtrl/Name/text()') as 'Control Name'

上面提到的轴之间的差异:

  • parent::element_name : 转到 one 级别到 specific 父元素

  • ancestor::element_name:进入一个或多个级别直到特定祖先元素

  • .. : 转到 one 级别到具有 any name[=20 的父元素=]

使用 nodes(), check the existence of Tag=34 for each shredded node using exist() and finally get the value from Form/TabCtrl/Name with the value() 函数在 Form/TabCtrl 上粉碎 XML。

select TC.X.value('(Name/text())[1]', 'nvarchar(100)')
from YourTable as T
  cross apply T.theXML.nodes('/Form/TabCtrl') as TC(X)
where TC.X.exist('*//Tag/text()[. = "34"]') = 1

SQL Fiddle