如何通过XName获取带命名空间前缀的XML中package元素?
OPF命名空间下XML元素查找问题解答
问题背景
我有如下XML文件,使用带前缀的命名空间xmlns:opf:
<?xml version="1.0" encoding="utf-8"?> <package version="2.0" unique-identifier="uuid_id" xmlns:opf="http://www.idpf.org/2007/opf"> <metadata xmlns:dcterms="http://purl.org/dc/terms/"> </metadata> </package>
尝试用以下C#代码通过XName获取package元素:
static void Main(string[] args) { using (MemoryStream stream = new MemoryStream(File.ReadAllBytes(@"C:\Users\xyz\Downloads\XMLs\X2.xml"))) { XDocument xDoc = XDocument.Load(stream); XNamespace opfNamespace = "http://www.idpf.org/2007/opf"; XElement packageElement = xDoc.Element(opfNamespace + "package"); Console.WriteLine($"packageElement is null - {packageElement == null}"); Console.WriteLine($"Prefix - [{xDoc.Root.GetPrefixOfNamespace(opfNamespace)}] Namespace - [{xDoc.Root.GetNamespaceOfPrefix("opf")}]"); foreach (var element in xDoc.Elements()) { Console.WriteLine($"Element: Namespace - [{element.Name.NamespaceName}] Name - [{element.Name.LocalName}]"); } } }
程序输出:
packageElement is null - True Prefix - [opf] Namespace - [http://www.idpf.org/2007/opf] Element: Namespace - [] Name - [package]
可见无法通过opfNamespace + "package"找到元素,调试发现element.Name不含命名空间。
疑问
- 如何无需手动遍历找到上述XML中的
package元素? - XML解析是否正确,
package元素无命名空间是否符合预期?
另外,当将命名空间改为默认命名空间后,代码可成功找到package元素:
测试XML:
<?xml version="1.0" encoding="utf-8"?> <package version="2.0" unique-identifier="uuid_id" xmlns="http://www.idpf.org/2007/opf"> <metadata xmlns:dcterms="http://purl.org/dc/terms/"> </metadata> </package>
输出:
packageElement is null - False Prefix - [] Namespace - [] Element: Namespace - [http://www.idpf.org/2007/opf] Name - [package]
解答
问题2:XML解析是否正确,package元素无命名空间是否符合预期?
解析完全正确,这是XML命名空间的基础规则:
xmlns:opf="http://www.idpf.org/2007/opf"只是定义了前缀opf和命名空间的映射关系,不会自动绑定到任何元素上。- 只有当元素使用
opf:前缀(例如<opf:package>)时,才会属于该命名空间。当前XML里的package元素没有前缀,自然不属于任何命名空间。 - 使用
xmlns="..."是定义默认命名空间,此时当前元素及其所有无前缀子元素都会自动归属该命名空间,这也是修改后代码能找到元素的原因。
问题1:如何无需手动遍历找到上述XML中的package元素?
因为package元素本身没有命名空间,直接用不带命名空间的元素名查找即可:
// 方法1:通过XName指定本地名称查找 XElement packageElement = xDoc.Element(XName.Get("package")); // 方法2:更简洁的写法,直接传入字符串(XName会自动识别无命名空间的情况) XElement packageElement = xDoc.Element("package");
如果后续需要处理该命名空间下的带前缀子元素(比如<opf:xxx>),再使用opfNamespace + "xxx"的方式查找即可。
内容的提问来源于stack exchange,提问作者ac-lap
相关产品推荐
相关产品推荐

