返回属性不包含特定字符的xml序列


10

考虑以下简单的XML:

<xml>
  <customer name="Max">
    <email address="me@you.com" />
  </customer>
  <customer name="Erik">
    <email address="erik@your-mom.com" />
  </customer>
  <customer name="Brent">
    <email address="brentcom" />
  </customer>
</xml>

我想获取<Customer>序列列表,其中address<email>项目的属性包含@

所以,我想要的输出看起来像:

<customer name="Brent">
  <email address="brentcom" />
</customer>

mcve

DECLARE @x XML = '<xml>
<customer name="Max"><email address="me@you.com" /></customer>
<customer name="Erik"><email address="erik@your-mom.com" /></customer>
<customer name="Brent"><email address="brentcom" /></customer>
</xml>';

该查询:

SELECT WithValidEmail = @x.query('/xml/customer/email[contains(@address, "@")]')
    , WithInvalidEmail = @x.query('/xml/customer/email[contains(@address, "@")] = False');

返回值:

╔═══════════════════════════════════════╦══════════════════╗
            WithValidEmail              WithInvalidEmail 
╠═══════════════════════════════════════╬══════════════════╣
 <email address="me@you.com" />                          
 <email address="erik@your-mom.com" />  false            
╚═══════════════════════════════════════╩══════════════════╝

该查询:

SELECT WithInValidEmail = @x.query('/xml/customer/email')
WHERE @x.exist('/xml/customer/email[contains(@address, "@")]') = 0;

返回值:

╔══════════════════╗
 WithInValidEmail 
╚══════════════════╝
    (no results)

WHERE上面查询中的子句消除了整个XML集,因为在电子邮件地址包含“ @”符号的地方至少存在一个序列。

Answers:


11

一种简单的方法是使用该nodes 方法直接访问address属性并检查@符号。

您现在使用的方式的问题在于,它仅检查是否有任何电子邮件地址@。通过解析XML节点,您可以检查各个电子邮件。

DECLARE @x XML
    = '<xml>
<customer name="Max"><email address="me@you.com" /></customer>
<customer name="Erik"><email address="erik@your-mom.com" /></customer>
<customer name="Brent"><email address="brentcom" /></customer>
</xml>';


SELECT x.c.value('@address', 'VARCHAR(100)') AS [email]
FROM   @x.nodes('/xml/customer/email') AS x(c)
WHERE  x.c.exist('@address[contains(., "@")]') = 0;

如果您需要使用这样的XML列查询实际的表,则只需CROSS APPLY使用node方法:

SELECT x.c.value('@address', 'VARCHAR(100)') AS [email]
FROM @x_table AS xt
CROSS APPLY xt.x.nodes('/xml/customer/email') AS x(c)
WHERE  x.c.exist('@address[contains(., "@")]') = 0;

如果要带回<customer>...</customer>该“行”的所有XML,则可以向后移动轴。请注意,回退会使大型XML块的性能降低。

SELECT x.c.query('..')
FROM @x_table AS xt
CROSS APPLY xt.x.nodes('/xml/customer/email') AS x(c)
WHERE  x.c.exist('@address[contains(., "@")]') = 0;

另一种方法是:

SELECT @x.query('/xml/customer[email/@address[not(contains(., "@"))]]') answer

移动方括号环绕电子邮件节点可以有效地使该WHERE子句适用于该customer节点。将此XQuery转换为英语看起来像:

让我得到所有xml/customer节点的email节点具有address不包含@符号的属性


4

你好近哦。使用该.query()函数和containsXQuery函数绝对可以使您步入正轨。您弄错的是:

  1. = False 外面[...](意思是,它不是部分contains()表达)
  2. 使用单词False代替函数false()
  3. 不通过添加/..到路径的末尾来指定父节点(这样结果将包括该<customer>元素而不仅仅是该<email>元素)

更正这三件事会导致以下XQuery表达式使您获得所需的内容:

'/xml/customer/email[contains(@address, "@") = false()]/..'

将其放入问题的原始示例中,即可得出:

DECLARE @x XML = '<xml>
<customer name="Max"><email address="me@you.com" /></customer>
<customer name="Erik"><email address="erik@your-mom.com" /></customer>
<customer name="Brent"><email address="brentcom" /></customer>
</xml>';

SELECT
@x.query('/xml/customer/email[contains(@address, "@")]/..') AS [WithValidEmail],
@x.query('/xml/customer/email[contains(@address, "@")=false()]/..') AS [WithInvalidEmail;

该查询返回一行包含两个XML字段的以下结果集:

WithValidEmail                            |     WithInvalidEmail
<customer name="Max">                     |     <customer name="Brent">
  <email address="me@you.com" />          |       <email address="brentcom" />
</customer>                               |     </customer>
<customer name="Erik">                    |
  <email address="erik@your-mom.com" />   |
</customer>                               |

这可能比使用该.nodes()功能分解文档更为有效,因为它可以一次性解析XML,而无需在每个节点上启动和停止解析器。

将其保留在其中的另一个好处.query()是您将返回一个XML文档。因此,如果您收到一个包含多个节点价值的XML文档/值,则可以保持标量值方法为单个实体,而不必将结果节点重新构造回文档中。这也使您可以在子查询/ CTE中使用它,而无需更改返回的预期行数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.