C#: 读取 XML 属性

4

使用C#2.0和VisualStudio2005

我正在试图从像下面这样的XML文件中访问”MonitorResponseRecord”内部的”DisplayName”:

    <Magellan xsi:schemaLocation="http://tempuri.org/XMLSchema.xsd ..\Schema\Configuration.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
      <SchemaVersion>1.0</SchemaVersion>
          <MonitorScope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="CleanStationChemicalManifoldFeed5" xmlns="http://tempuri.org/XMLSchema.xsd">
            <PersonalSafety>
              <MonitorResponseRecord Enabled="true" DisplayName="ChemicalManifoldFeed5ControllerFault">
                <ExpressionMonitor>
                  <Expression>(ChemicalManifold.Feed5.DispenseValve = Open) and ((ChemicalManifold.Feed5.ViolatedRegion = HighProcess) or (ChemicalManifold.Feed5.ViolatedRegion = LowProcess) or (ChemicalManifold.Feed5.ViolatedRegion = Minimum))</Expression>
                  <TestInterval>0.1</TestInterval>
                  <MinimumTimeBetweenResponses>5</MinimumTimeBetweenResponses>
                </ExpressionMonitor>
                <Response>
                  <PostAlarm>
                    <AlarmName>ChemicalManifold_Feed5_ControllerFault</AlarmName>
                    <Parameter1 />
                    <Parameter2>Alarm Region = {ChemicalManifold.Feed5.ViolatedRegion}</Parameter2>
                    <Parameter3>{RecipeName}-{StepName}</Parameter3>
                    <Parameter4>FlowSetpoint = {ChemicalManifold.Feed5.Setpoint}-LPM, ActualFlow = {ChemicalManifold.Feed5.FlowMeter}-LPM</Parameter4>
                  </PostAlarm>
                  <ResponseEvent>
                    <TargetResource />
                    <Event>PA</Event>
                    <Reason>ChemicalSupply</Reason>
                  </ResponseEvent>
                </Response>
              </MonitorResponseRecord>
            </PersonalSafety>
            <PersonalSafety>
              <MonitorResponseRecord Enabled="true" DisplayName = "PressureValveFailure">
           ...
            ...                
             ...and soon

我当前的 C# 尝试如下,但每当我尝试 XmlDocument.Load(""); 时它总是卡住。

                XmlDocument doc = new XmlDocument();
                doc.Load("../UMC0009.Configuration.Root.xml");
                string attrVal = doc.SelectSingleNode("MonitorResponseRecord/@DisplayName").Value;
                

但是它不起作用:/ 有任何帮助吗?

更新:

我收到的异常如下,在doc.Load("...")行发生:

{"需要命名空间管理器或XsltContext。此查询具有前缀、变量或用户定义的函数。"} System.Exception {System.Xml.XPath.XPathException}


2
如果它在加载时“挂起”,那么它不喜欢你提供的路径。尝试使用完整路径! - banging
很不幸,没有任何改变 :( - Medic3000
正如@banging所暗示的那样:如果你在Load(...)上“挂起”,那么你应该会收到一个异常。请告诉我们这个异常是什么! :) - IAbstract
"需要命名空间管理器或XsltContext。此查询具有前缀、变量或用户定义的函数。" System.Exception {System.Xml.XPath.XPathException} - Medic3000
1
你确定Load()方法会抛出那个异常吗?因为Load()只会抛出XmlExceptions异常,而抛出XPathException异常的方法是SelectSingleNode()!Adolfo的回答似乎是你需要的 ;) - banging
2个回答

5

您的XPath查询将相对于文档根:

doc.SelectSingleNode("MonitorResponseRecord/@DisplayName")

为了使搜索在文档中任何地方进行,请在前面加上双斜杠:

doc.SelectSingleNode("//MonitorResponseRecord/@DisplayName")

如果仍然无法正常工作,我建议您尝试在两个根节点上剥离所有命名空间声明后,再按照上面的示例进行操作。
否则,如果存在命名空间声明,您可能需要定义XML命名空间映射,并在XPath中使用前缀,例如:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("x", "http://tempuri.org/XMLSchema.xsd");

doc.SelectSingleNode("//x:MonitorResponseRecord/@DisplayName")

你的回答给了我一个异常: {"需要命名空间管理器或XsltContext。此查询具有前缀、变量或用户定义的函数。"} System.Exception {System.Xml.XPath.XPathException} - Medic3000
1
我稍微更新了第三个片段,属性上不应该有前缀。你试过我说的去除命名空间声明吗?另外,XML文件大小是多少?它是否因为太大而挂起? - KrisG
1
@KrisG,当您在XPath表达式中使用命名空间前缀时,还需要提供一个XmlNamespaceManager实例(这是DarthSheldon评论中指出的异常)。请参阅SelectSingleNode文档页面上的示例以了解如何执行此操作;您可能需要相应地更新第三个代码片段。(如果我理解正确,您可能需要再次向属性添加前缀...,因为DisplayName是默认命名空间中的属性,就像MonitorResponseRecord元素一样。) - O. R. Mapper
谢谢 O. R. Mapper,我已经添加了命名空间映射逻辑。 - KrisG
感谢O.R. Mapper和KrisG,我会尝试这个方法。@KrisG关于.xml文件大小,它是1.1Mb,相当大,这可能导致挂起吗?如果是这样,我该怎么做才能解决呢? - Medic3000
现在它会给出以下异常:如果我在你的第三段代码之前有doc.Load(.../.../)这一行,我会得到:{"无法找到文件D:\OR\B\Xml\CustomerSpecific\UMC0009.Configuration.Root.xml'。":"D:\OR\B\Xml\CustomerSpecific\UMC0009.Configuration.Root.xml"} System.Exception {System.IO.FileNotFoundException}否则,如果没有那一行,我仍然会在.AddNamespace()这一行上收到异常:{因为先前的函数评估超时而禁用了函数评估,您必须继续执行以重新启用函数评估。} System.Exception {System.Xml.XPath.XPathException} - Medic3000

1

关于这个问题怎么看?

    XmlDocument doc = new XmlDocument();
    doc.Load("UMC0009.Configuration.Root.xml");

    XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
    nsmgr.AddNamespace("ns", "http://tempuri.org/XMLSchema.xsd");
    string attrVal = doc.SelectSingleNode("//ns:MonitorResponseRecord/@DisplayName", nsmgr).Value;

使用命名空间管理器,指定您的命名空间URI并在XPath中使用它。 这对我很有效。

我本想这样做,但我的程序在 doc.Load() 处卡住了,跳到异常处理,跳过了它下面的所有内容。 - Medic3000
@DarthSheldon:在你的回答中发布你遇到的异常。 - IAbstract
请将您的逻辑放置在try/catch块中并发布您获得的异常。 - Adolfo Perez
已经在 try/catch 块中,我收到的异常是:{"需要命名空间管理器或 XsltContext。此查询具有前缀、变量或用户定义的函数。"} System.Exception {System.Xml.XPath.XPathException} - Medic3000
让我们在聊天室里继续这个讨论 - Medic3000
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接