T-SQL查询XML:如何按名称而非索引获取UserArea的Property属性?
解决XML中通过属性名称获取UserArea节点值的问题
你当前通过索引*:Property[4]获取Manufacturer值的方式依赖节点顺序,一旦节点缺失或顺序变动就会出错。正确的做法是通过NameValue的name属性筛选目标节点,而非依赖索引。
错误原因分析
你尝试的绝对路径(/SyncPurchaseOrder/DataArea/PurchaseOrder/PurchaseOrderLine/UserArea/Property/NameValue[@name="Manufacturer"])[5]存在两个问题:
- 使用了绝对路径,会遍历整个XML的所有PurchaseOrderLine节点,而非当前通过
nodes()定位的单个节点; - 末尾的
[5]索引是全局索引,不符合每个PurchaseOrderLine独立取值的需求。
正确写法
利用相对路径结合属性筛选,在value()函数中定位到当前PurchaseOrderLine节点下的目标属性:
s.PO.value('(*:UserArea/*:Property/*:NameValue[@name="Manufacturer"])[1]', 'nvarchar(50)')
*:前缀保留,适配XML可能存在的默认命名空间;[@name="Manufacturer"]精准筛选出name属性为Manufacturer的NameValue节点;[1]确保只取当前节点下第一个匹配的结果(避免同一节点下重复属性)。
修改后的完整代码
Declare @POXML as XML Set @POXML = '<SyncPurchaseOrder releaseID="9.2"> <DataArea> <PurchaseOrder> <PurchaseOrderLine> <LineNumber>1</LineNumber> <UserArea> <Property> <NameValue name="ActiveFlag">true</NameValue> </Property> <Property> <NameValue name="ExchangeRate">1.00</NameValue> </Property> <Property> <NameValue name="UDFCHAR02"/> </Property> <Property> <NameValue name="Manufacturer">SHA</NameValue> </Property> <Property> <NameValue name="ManufacturerPart">16710761-001</NameValue> </Property> <Property> <NameValue name="TransactionNumber"/> </Property> <Property> <NameValue name="TransactionLine"/> </Property> <Property> <NameValue name="UDFNUM02">2</NameValue> </Property> </UserArea> </PurchaseOrderLine> <PurchaseOrderLine> <LineNumber>2</LineNumber> <UserArea> <Property> <NameValue name="ActiveFlag">true</NameValue> </Property> <Property> <NameValue name="ExchangeRate">1.00</NameValue> </Property> <Property> <NameValue name="UDFCHAR02"/> </Property> <Property> <NameValue name="Manufacturer">MIS</NameValue> </Property> <Property> <NameValue name="ManufacturerPart">20021676+80</NameValue> </Property> <Property> <NameValue name="TransactionNumber"/> </Property> <Property> <NameValue name="TransactionLine"/> </Property> <Property> <NameValue name="UDFCHAR11">18275884-001</NameValue> </Property> <Property> <NameValue name="UDFNUM02"/> </Property> </UserArea> </PurchaseOrderLine> </PurchaseOrder> </DataArea> </SyncPurchaseOrder>' drop table if exists #reqOnPo select s.PO.value('(*:UserArea/*:Property/*:NameValue[@name="Manufacturer"])[1]', 'nvarchar(50)') as MFG into #reqOnPo from @POXML.nodes('./*:SyncPurchaseOrder/*:DataArea/*:PurchaseOrder/*:PurchaseOrderLine') as s(PO) select * from #reqonpo
额外说明
如果XML存在明确的命名空间,建议先声明命名空间变量,写法会更清晰:
;WITH XMLNAMESPACES(DEFAULT 'http://your-namespace-uri') select s.PO.value('(UserArea/Property/NameValue[@name="Manufacturer"])[1]', 'nvarchar(50)') as MFG into #reqOnPo from @POXML.nodes('SyncPurchaseOrder/DataArea/PurchaseOrder/PurchaseOrderLine') as s(PO)
内容的提问来源于stack exchange,提问作者LJHHouston
相关产品推荐
相关产品推荐

