如何正确使用Windows::Data::Xml::Dom GetNamedItemNS提取命名空间属性值?
默认命名空间下提取XML属性的问题解决方法
问题重现
给定以下带默认命名空间的XML:
<?xml version="1.0" encoding="UTF-8"?> <Thing xmlns="https://thing"> <Foos> <Bars> <Bar title="Firefox" description="You need firefox"> </Bar> <Bar title="Chrome" description="You need chrome"> </Bar> </Bars> </Foos> </Thing>
使用WinRT代码遍历<Bar>元素并提取title属性时,调用GetNamedItemNS始终返回NULL:
auto nss = winrt::box_value(L"xmlns:sv='https://thing'"); auto ns = winrt::box_value(L"https://thing"); for (Windows::Data::Xml::Dom::IXmlNode node : document.SelectNodesNS(L"/sv:Things/sv:Foos/sv:Bars/sv:Bar", nss)) { auto attrs = node.Attributes(); auto titleNode = attrs.GetNamedItemNS(ns, L"title"); if (!titleNode) { // titleNode is NULL - why? continue; } }
核心问题分析
- XPath拼写错误:XPath表达式中写的是
/sv:Things,但XML根元素是<Thing>(单数),这会导致无法正确选中目标节点,需修正为/sv:Thing/sv:Foos/sv:Bars/sv:Bar。 - 属性的命名空间规则:XML中属性默认不会继承元素的默认命名空间,只有当属性显式使用前缀声明时,才属于对应命名空间。你的
title属性没有前缀,因此不属于https://thing命名空间,用GetNamedItemNS传入命名空间参数自然匹配不到。
正确解决方案
方案1:直接使用无命名空间的方法获取属性
因为title属性不属于任何命名空间,直接调用GetNamedItem方法即可:
auto titleNode = attrs.GetNamedItem(L"title");
方案2:若需属性属于默认命名空间(需修改XML)
如果业务要求属性必须属于https://thing命名空间,需要在XML中给属性添加对应前缀(同时声明前缀):
<?xml version="1.0" encoding="UTF-8"?> <Thing xmlns:sv="https://thing" xmlns="https://thing"> <Foos> <Bars> <Bar sv:title="Firefox" sv:description="You need firefox"> </Bar> </Bars> </Foos> </Thing>
此时再用GetNamedItemNS传入命名空间参数就能正确获取:
auto titleNode = attrs.GetNamedItemNS(ns, L"title");
修正后的完整代码示例
auto nss = winrt::box_value(L"xmlns:sv='https://thing'"); // 修正XPath的根元素名称 for (Windows::Data::Xml::Dom::IXmlNode node : document.SelectNodesNS(L"/sv:Thing/sv:Foos/sv:Bars/sv:Bar", nss)) { auto attrs = node.Attributes(); // 使用GetNamedItem直接获取无命名空间的属性 auto titleNode = attrs.GetNamedItem(L"title"); if (titleNode) { // 处理title属性值 hstring title = titleNode.InnerText(); } }
内容的提问来源于stack exchange,提问作者Graham Leggett
相关产品推荐
相关产品推荐

