1

我不熟悉 XPath,我正在寻找有关从文件中简单地选择三个值的指导:架构版本、标题和描述。

当我从和//title/langstring中删除名称间距信息时,Xpath 表达式仅匹配元素值。<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;
    } 
4

1 回答 1

0

您遇到的问题是您尝试选择的元素实际上属于某个命名空间,但您在选择它时没有指定命名空间。和元素titlelangstring属于默认命名空间。在 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);

然而,诀窍是XmlNameTableXmlNamespaceManager. 不幸的是,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);

或者,您可以使用XmlDocumentwhich 在处理命名空间时稍微容易一些。或者,您也可以选择使用 LINQ 而不是 XPath 来选择元素。

于 2013-08-30T14:06:10.837 回答