【问题标题】:How to read a processing instruction from XML string using C# .NET?如何使用 C# .NET 从 XML 字符串中读取处理指令?
【发布时间】:2020-09-08 13:16:04
【问题描述】:

我想从一些小的well-formed XML 块中读取processing instruction,基于这篇文章:How to read processing instruction from an XML file using .NET 3.5

但是,它不起作用。我收到错误消息,即 pi 对象为空。 我就是这样做的:

XmlDocument doc = new XmlDocument();
doc.LoadXml("<root>Text <?pi 1?>blabla</root>");
Console.WriteLine(doc.ChildNodes[0].Name); // output: root

XmlProcessingInstruction pi = doc.OfType<XmlProcessingInstruction>().Where(x => x.Name == "pi").FirstOrDefault();
Console.WriteLine(pi.Value);

解析 XML 有效。当我在 Visual Studio 中收到错误 (System-NullReferenceException) 时,我在行“Console.WriteLine(pi.Value);”中得到它。

哪里出错了?如何获取/读取处理指令?

【问题讨论】:

  • 这看起来不像是一个有效的 xml。
  • 它是格式良好的 XML。是否必须有效才能访问 PI?当我检查 XmlDocument 对象时,它显示了一个成功的解析树。
  • 它不是一个有效的 XML,或者至少它不是一个有效的处理指令。试试doc.LoadXml("&lt;?xml-stylesheet type=\"text/xsl\" href=\"Sample.xsl\"?&gt;&lt;Root&gt;&lt;Child/&gt;&lt;/Root&gt;")
  • “有效的 XML”和“格式正确的 XML”是有区别的。请参考。 en.wikipedia.org/wiki/Well-formed_document 进行解释。上面的代码使用格式良好的 XML。这没有错。我还尝试更改代码并在开头添加 标记和一个子元素(只是为了确定),但没有更改。您的示例代码也不包含处理指令(参见en.wikipedia.org/wiki/Processing_Instruction)。

标签: c# xml parsing


【解决方案1】:

您的代码中有两个问题。

第一个是它在Console.WriteLine(doc.ChildNodes[1].Name); 上失败,“root”是第一个节点,而不是第二个(从零开始)。但这可能是一个错字。

关于问题:

Enumerable.OfType() 正在使用由其父级 XmlNode.GetEnumerator() 实现的 XmlDocument 类的 GetEnumerator()。文档指出:

一个 IEnumerator 对象,可用于遍历当前节点中的子节点。

但您正试图在 doc 上运行 OfType,他只有一个孩子:root

如果您将代码更改为在 root 的孩子上运行,它将按预期工作:

XmlProcessingInstruction pi = doc.ChildNodes[0].OfType<XmlProcessingInstruction>().Where(x => x.Name == "pi").FirstOrDefault();

【讨论】:

  • 另外,我可以建议一种调试策略,我用来发现您的问题的那个:在您的情况下,似乎pi 为空是问题所在。但这仅仅是因为FirstOrDefault() 将返回 null 以防万一它没有第一个。如果您将表达式分解为单独的变量并检查每个步骤,您会发现doc.OfType&lt;XmlProcessingInstruction&gt;() 返回一个空的可枚举。每次看到 Linq 表达式不符合我的要求时,我都会先将其拆分以确保没有遗漏任何内容。
  • 谢谢。是的,索引是一个错字。我喜欢调试策略。
【解决方案2】:

使用 XmlDocument:

var doc = new XmlDocument();
doc.Load("test.xml");

// get all instructions
var instructions = doc.SelectNodes("//processing-instruction()");

foreach (XmlProcessingInstruction instruction in instructions)
    Console.WriteLine(instruction.Target + " : " + instruction.Data);

// get concrete instruction
var pi = doc.SelectSingleNode("//processing-instruction('pi')") as XmlProcessingInstruction;
Console.WriteLine(pi.Target + " : " + pi.Data);

LINQ to XML。它更方便、更容易:

var xml = XDocument.Load("test.xml");

var instructions = xml.DescendantNodes()
    .OfType<XProcessingInstruction>();

foreach (var instruction in instructions)
    Console.WriteLine(instruction);

var pi = instructions.FirstOrDefault(x => x.Target == "pi");
Console.WriteLine(pi.Data);

【讨论】:

    【解决方案3】:

    我能够让它这样工作:

     static void Main(string[] args)
       {
        XmlDocument doc = new XmlDocument();
        doc.Load("c:\\test\\xmlData.xml");
                 
       List<XmlProcessingInstruction> piList = new List<XmlProcessingInstruction>(); 
          foreach (XmlNode cnode in doc.ChildNodes)
           {
             foreach (var ccnode in cnode)
             {
               if (ccnode is XmlProcessingInstruction)
                   piList.Add(ccnode as XmlProcessingInstruction);
             }
          }
          Console.WriteLine(piList.FirstOrDefault(a => a.Name == "pi").Value);
       }
    

    xmlData.xml

       <?xml version="1.0" encoding="utf-8"?>
         <root>
         <?pi 1?>
           <value>6</value>
         </root>
    

    我认为您无法获得 pi 的原因是您的 Pi 目标和值周围没有引号。我无法让它作为字符串工作,但它可以很好地从文件中读取。

    【讨论】:

      【解决方案4】:
      {
          private float _length;
          private int _toeCount;
      
      
          public Socks()
          { //code here;
          }
      
          public override bool Equals(object obj)
          {
              if (!(obj is Socks arg)) return false;
      
              return (this._length.Equals(arg._length));
          }
      
          public override int GetHashCode()
          {
              return 1;
          }
      
          public static int SortByWidthToe(Socks a, Socks b)
          {
              if (a == null && b == null) return 0;
              if (a == null) return -1;
              if (b == null) return 1;
      
              if (a._length.Equals(b._length))
                  return a._toeCount.CompareTo(b._toeCount);
      
              return a._length.CompareTo(b._length);
          }
      }
      

      【讨论】:

      • 用一些解释围绕你的代码会大大改善你的答案。
      猜你喜欢
      • 2011-03-07
      • 1970-01-01
      • 2015-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-22
      • 1970-01-01
      • 2016-08-28
      相关资源
      最近更新 更多