我需要在SQL Server中扩展xml作为表。我使用XQuery
和nodes()
以及.query()
来执行此操作。但我需要每个节点都有一个序列号,我还需要根据内部结构过滤节点,我不知道如何做到这一点。
我需要以下结果:
------------------------
| 1 | <xml node ...> |
------------------------
| 2 | <xml node ...> |
------------------------
...
我有以下XML:
<node xmlns="http://mynamespace.com/ns/">
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Domain</Tag>
<Value>dom</Value>
</subnode>
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Wdth</Tag>
<Value>1</Value>
</subnode>
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Code</Tag>
<Value>TEST</Value>
</subnode>
</node>
<node xmlns="http://mynamespace.com/ns/">
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Domain</Tag>
<Value>dom</Value>
</subnode>
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Wdth</Tag>
<Value>1</Value>
</subnode>
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Code</Tag>
<Value></Value>
</subnode>
</node>
当<Tag>Code</Tag>
的值为空(<Value></Value>
)时,我需要跳过此节点。
我使用以下代码,但我无法弄清楚如何制作序列号或如何过滤:
DECLARE @XMLInput XML = '<node xmlns="http://mynamespace.com/ns/">
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Domain</Tag>
<Value>dom</Value>
</subnode>
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Wdth</Tag>
<Value>1</Value>
</subnode>
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Code</Tag>
<Value>TEST</Value>
</subnode>
</node>
<node xmlns="http://mynamespace.com/ns/">
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Domain</Tag>
<Value>dom</Value>
</subnode>
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Wdth</Tag>
<Value>1</Value>
</subnode>
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Code</Tag>
<Value></Value>
</subnode>
</node>';
SELECT
Child.query('declare default element namespace "http://mynamespace.com/ns/"; (.)') AS node
FROM
@XMLInput.nodes('declare default element namespace "http://mynamespace.com/ns/"; (/node)') AS N(Child)
修改
因为我澄清了不清楚的要素。当存在<node>
节点且<subnode>
节点的值为<Tag>
且对应的"Code"
节点为空时,我需要过滤掉整个<Value>
节点。在这种情况下,我需要移除整个<node>
- 不可见。
答案 0 :(得分:1)
第一部分相当简单,使用ROW_NUMBER() OVER()
。由于XML具有隐式排序顺序,因此我们可以使用(SELECT NULL)
。行将根据XML中的物理顺序显示:
使用此代码,您的节点将被编号:
WITH XMLNAMESPACES(DEFAULT 'http://mynamespace.com/ns/')
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS NodeNr
,Child.query('.') AS node
FROM
@XMLInput.nodes('/node') AS N(Child)
你的第二部分对我来说并不清楚。你想完全压制第二个节点,因为有
<subnode xmlns="http://mynamespace.com/ns/">
<Tag>Code</Tag>
<Value></Value>
</subnode>
?或者你想要仅仅抑制这个<subnode>
?
以下内容将使用upper作为派生表(CTE
),然后在列.exist()
上使用node
。该方法仅根据XQuery
表达式检查任何节点的存在。在这种情况下,我使用<Tag>
搜索任何text()="Code"
。从那里我们向上导航一级并搜索<Value>
为空的text()
元素。如果存在,则函数返回1
,因此我们需要那些没有:
WITH XMLNAMESPACES(DEFAULT 'http://mynamespace.com/ns/')
,shredded AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS NodeNr
,Child.query(N'.') AS node
FROM
@XMLInput.nodes(N'/node') AS N(Child)
)
SELECT *
FROM shredded
WHERE shredded.node.exist(N'//Tag[text()="Code"]/../Value[empty(text())]')=0
正如@MartinSmith指出的那样,没有证据证明这个
行将根据XML中的物理顺序显示
同时我发现了这个:
我在XML in SQL Server 2005找到了一篇论文。在那里你可以找到 XML值以内部格式存储...以支持XML模型特征,例如文档顺序... 这至少是一个提示,即文档的订单是持久的。使用FROM OPENXML
读取XML也将返回一个已排序的表(至少我还没有找到任何异常)。
我发现了Understanding the XML data type。您可以在哪里找到此内部表示包括有关包含层次结构,文档顺序以及元素和属性值的信息。具体而言,保留XML数据的InfoSet内容。
关于InfoSet
I found this document,其中说明了[children]
:子信息项的有序列表,按文档顺序。
嗯,这仍然没有有效的证明,SELECT
.nodes()
将在所有情况下以与 XML中的完全相同的顺序返回派生表。但是 - 至少 - 它指出了内部秩序值得坚持的事实。
我的结论:内部订单被视为XML文档的固有部分。这就是为什么我很确定,.nodes()
将以相同的顺序返回派生表。添加ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
除了向这些行添加运行编号之外什么都不做。