C# 使用XPath和C处理IMSManifest.xml#

C# 使用XPath和C处理IMSManifest.xml#,c#,.net,xml,xpath,C#,.net,Xml,Xpath,我不熟悉XPath,我正在寻找关于从文件中简单选择三个值的指导:schemaversion、title和description 当我从和中去掉名称间距信息时,Xpath表达式//title/langstring仅与元素值匹配 在内容中搜索这些值的正确方法是什么 单元测试: [Test] public void TitleIsNotNull() { var manifestManager = new ManifestManager("imsmanifest.xml"); // Code w

我不熟悉XPath,我正在寻找关于从文件中简单选择三个值的指导:schemaversion、title和description

当我从
中去掉名称间距信息时,Xpath表达式
//title/langstring
仅与元素值匹配

在内容中搜索这些值的正确方法是什么

单元测试:

[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);
}
_内容(节选):

//私人助手

    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);
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);
然而,诀窍是让
XmlNameTable
提供给
XmlNamespaceManager
。不幸的是,
XElement
类没有为文档提供获取
XmlNameTable
的方法,因此最好通过
XmlReader
加载它,它可以提供如下功能:

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);
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。

Steven我不确定我搞错了什么,但该值返回null并且未通过我的测试。为了让它在我这方面起作用,我还必须删除
schemalocation
属性。试试看它是否能帮你解决问题。如果是这样的话,那就是问题的第二部分所在。我能够添加一个新的名称空间声明
xmlNamespaceManager.AddNamespace(“y”)http://www.imsglobal.org/xsd/imsmd_rootv1p2p1");
查找嵌套在
元素下的元素。我修改了我的问题,加入了你的修正,我接受了你的回答。非常感谢。