SQL中解析带命名空间的XML为何需添加p1命名空间声明?
关于XML命名空间与XQuery查询的问题
问题背景
SQL表某列存储的XML文档如下(含命名空间声明):
<?xml version="1.0" encoding="utf-16"?> <AppMgmtDigest xmlns="http://schemas.microsoft.com/SystemCenterConfigurationManager/2009/AppMgmtDigest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Application AuthoringScopeId="ScopeId_932201A0-0C33-4C2C-9723-2975C4CCEBB5" LogicalName="Application_0e2a35f6-49a1-403f-adf5-d9f393571943" Version="4"> <DisplayInfo DefaultLanguage="en-US"> <Info Language="en-US"> <Title>Microsoft Office Excel Viewer</Title> </Info> </DisplayInfo> <DeploymentTypes> <DeploymentType AuthoringScopeId="ScopeId_932201A0-0C33-4C2C-9723-2975C4CCEBB5" LogicalName="DeploymentType_04fa8891-e832-486f-8d72-fc77c7dcffda" Version="3"/> </DeploymentTypes> <Title ResourceId="Res_1963789643">Microsoft Office Excel Viewer</Title> <AutoInstall>true</AutoInstall> <Owners> <User Qualifier="LogonName" Id="abc123"/> </Owners> <Contacts> <User Qualifier="LogonName" Id="abc123"/> </Contacts> </Application> <DeploymentType AuthoringScopeId="ScopeId_932201A0-0C33-4C2C-9723-2975C4CCEBB5" LogicalName="DeploymentType_04fa8891-e832-486f-8d72-fc77c7dcffda" Version="3"> ... </DeploymentType> </AppMgmtDigest>
执行以下XQuery语句无结果:
SomeName.value('declare namespace p1="http://schemas.microsoft.com/SystemCenterConfigurationManager/2009/AppMgmtDigest";(p1:AppMgmtDigest/p1:DeploymentType)[1]', 'nvarchar(max)') as Test
但以下语句可正常工作:
someVar.value('declare namespace p1="http://schemas.microsoft.com/SystemCenterConfigurationManager/2009/AppMgmtDigest";(p1:AppMgmtDigest/p1:Application/p1:AutoInstall)[1]', 'nvarchar(max)') = 'true'
疑问:为何必须添加p1命名空间声明?
解答
1. 为什么必须加命名空间声明?
XML命名空间的核心作用是区分不同上下文下的同名元素——比如不同业务系统或标准里可能都有<Application>标签,但它们的含义完全不同,命名空间就是给这些元素打上“归属标签”。
你提供的XML里,根元素AppMgmtDigest通过xmlns="http://..."声明了默认命名空间,这意味着XML里所有没有显式指定其他命名空间的元素(包括<Application>、<DeploymentType>、<AutoInstall>等)都属于这个默认命名空间。
而XQuery的规则是:如果查询时不指定命名空间,会默认匹配无命名空间的元素——但你的XML里所有元素都属于那个默认命名空间,所以不声明的话,XQuery找不到任何匹配的元素,自然返回null或无结果。
用declare namespace p1="..."就是把这个命名空间绑定到前缀p1,之后用p1:前缀去引用元素,XQuery才能识别到这些元素属于目标命名空间,从而正确匹配。
2. 为什么第一个查询无结果?
看你的XML结构,直接在AppMgmtDigest下的DeploymentType元素是存在的,但查询无结果可能有两个原因:
- XML标签的语法问题:你提供的XML里根元素写的是
< AppMgmtDigest ...>(注意标签名前有空格),这属于无效的XML标签名(XML标签名不能包含空格),如果实际存储的XML就是这样,会导致XQuery无法识别根元素,自然找不到后续的DeploymentType。 value()方法的返回限制:value()方法要求查询返回单个原子值,而你查询的是整个DeploymentType元素(包含属性和子元素),如果要返回元素的XML内容,应该用query()方法,比如:
SomeName.query('declare namespace p1="http://schemas.microsoft.com/SystemCenterConfigurationManager/2009/AppMgmtDigest";p1:AppMgmtDigest/p1:DeploymentType[1]') as Test
内容的提问来源于stack exchange,提问作者AnthonyC
相关产品推荐
相关产品推荐

