使用 XPath 和 C# 处理 IMSManifest.xml
本文关键字:IMSManifest xml 处理 XPath 使用 | 更新日期: 2023-09-27 18:29:35
我不熟悉 XPath,我正在寻找有关从文件中简单地选择三个值的指导:架构版本、标题和描述。
Xpath 表达式//title/langstring
仅在我从 <manifest>
和 <lom>
中删除名称间距信息时才匹配元素值。
搜索这些值内容的正确方法是什么?
单元测试:
[Test]
public void TitleIsNotNull()
{
var manifestManager = new ManifestManager("imsmanifest.xml");
// Code which initializes object and calls GetTitle() is encapsulated.
Assert.IsNotNullOrEmpty(manifestManager.Title);
}
被测系统:
private string GetTitle()
{
var document = XElement.Parse(_contents);
const string XpathExpression = "//title/langstring";
return (string)document.XPathSelectElement(XpathExpression);
}
_contents(摘录(:
<?xml version="1.0" encoding="utf-8"?>
<manifest xsi:schemaLocation="http://www.imsproject.org/xsd/imscp_rootv1p1p2
imscp_rootv1p1p2.xsd
http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 imsmd_rootv1p2p1.xsd
http://www.adlnet.org/xsd/adlcp_rootv1p2 adlcp_rootv1p2.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2"
xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2"
version="1.0"
identifier="ExampleIdGoesHere">
<metadata>
<schema>ADL SCORM</schema>
<schemaversion>1.2</schemaversion>
<lom xsi:schemaLocation="http://www.imsglobal.org/xsd/imsmd_rootv1p2p1
imsmd_rootv1p2p1.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.imsglobal.org/xsd/imsmd_rootv1p2p1">
<general>
<title>
<langstring xml:lang="x-none">Example title goes here.</langstring>
</title>
<description>
<langstring xml:lang="x-none">Example description goes here.</langstring>
</description>
</general>
</lom>
</metadata>
基于Steven Doggart解决方案的调整代码
//修订
private string GetTitle()
{
var xmlReader = GetXmlReader();
var document = XElement.Load(xmlReader);
var xmlNamespaceManager = GetXmlNamespaceManager(xmlReader);
const string XpathExpression = "//y:title/y:langstring";
return (string)document.XPathSelectElement(XpathExpression, xmlNamespaceManager);
}
私人助手
private XmlReader GetXmlReader()
{
var contents = new StringReader(_contents);
var xmlReader = XmlReader.Create(contents);
return xmlReader;
}
private XmlNamespaceManager GetXmlNamespaceManager(XmlReader xmlReader)
{
if (xmlReader.NameTable != null)
{
var xmlNamespaceManager = new XmlNamespaceManager(xmlReader.NameTable);
xmlNamespaceManager.AddNamespace("x", "http://www.imsproject.org/xsd/imscp_rootv1p1p2");
xmlNamespaceManager.AddNamespace("y", "http://www.imsglobal.org/xsd/imsmd_rootv1p2p1");
return xmlNamespaceManager;
}
return null;
}
您遇到的问题是,您尝试选择的元素实际上属于某个命名空间,但是您在选择它时没有指定命名空间。 title
和 langstring
元素都属于默认命名空间。 在 XML 文档中,默认命名空间定义为 "http://www.imsproject.org/xsd/imscp_rootv1p1p2"
。 使用 XPath,无法指定默认命名空间。 如果您不提供命名空间,则始终假定您根本没有命名空间。 因此,若要选择该元素,必须显式提供命名空间,如下所示:
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(nameTable);
namespaceManager.AddNamespace("x", "http://www.imsproject.org/xsd/imscp_rootv1p1p2");
const string XpathExpression = "//x:title/x:langstring";
return (string)document.XPathSelectElement(XpathExpression, namespaceManager);
然而,诀窍是让XmlNameTable
给XmlNamespaceManager
. 不幸的是,XElement
类没有提供获取文档XmlNameTable
的方法,因此最好的选择是通过 XmlReader
加载它,它可以提供,如下所示:
XmlReader reader = XmlReader.Create(new StringReader(_contents));
XElement document = XElement.Load(reader);
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(reader.NameTable);
namespaceManager.AddNamespace("x", "http://www.imsproject.org/xsd/imscp_rootv1p1p2");
const string XpathExpression = "//x:title/x:langstring";
return (string)document.XPathSelectElement(XpathExpression, namespaceManager);
或者,您可以使用XmlDocument
,这在处理命名空间时稍微容易一些。 或者,您也可以选择使用 LINQ 而不是 XPath 来选择元素。