【问题标题】:Check well-formed XML without a try/catch?检查格式正确的 XML 而不使用 try/catch?
【发布时间】:2010-11-04 19:17:48
【问题描述】:

有谁知道如何检查字符串是否包含格式正确的 XML,而无需在 try/catch 块中使用 XmlDocument.LoadXml() 之类的东西?我的输入可能是 XML 也可能不是 XML,我希望代码能够识别输入可能不是 XML,而不依赖于 try/catch,无论是速度还是非异常情况不应引发的一般原则例外。我目前有执行此操作的代码;

private bool IsValidXML(string value)
    {
        try
        {
            // Check we actually have a value
            if (string.IsNullOrEmpty(value) == false)
            {
                // Try to load the value into a document
                XmlDocument xmlDoc = new XmlDocument();

                xmlDoc.LoadXml(value);

                // If we managed with no exception then this is valid XML!
                return true;
            }
            else
            {
                // A blank value is not valid xml
                return false;
            }
        }
        catch (System.Xml.XmlException)
        {
            return false;
        }
    }

但这似乎不需要 try/catch。该异常在调试过程中引起了快乐的地狱,因为每次我检查一个字符串时,调试器都会在这里中断,“帮助”我解决我讨厌的问题。

【问题讨论】:

  • 如果调试器是您的问题,您可以关闭用户对 XmlExceptions 的处理。使用 VS 中的快捷键:Ctrl + Alt + E,找到 System.Xml.XmlException 并将其关闭。
  • 令人惊讶的是,每一个答案都是尝试/捕获的答案;尽管您明确指出,但您正在寻找没有 try/catch 的解决方案。 Try/catch 不是 IF 语句;它不应成为该过程的一部分。它用于处理异常。从名字上看有点明显:)我希望你有一天能找到一个好的答案。

标签: c# xml well-formed


【解决方案1】:

我不知道没有例外的验证方法,但是您可以将调试器设置更改为仅在未处理的情况下中断XmlException - 即使代码仍然不优雅,这应该可以解决您的直接问题。

为此,请转到 Debug / Exceptions... / Common Language Runtime Exceptions 并找到 System.Xml.XmlException,然后确保仅勾选“User-unhandled”(而不是 Throw)。

【讨论】:

  • +1 为这个拯救生命的解决方案。如果我必须调试失败的代码,我只启用中断处理的异常。
【解决方案2】:

史蒂夫,

我们有一个第 3 方不小心有时会向我们发送 JSON 而不是 XML。这是我实现的:

public static bool IsValidXml(string xmlString)
{
    Regex tagsWithData = new Regex("<\\w+>[^<]+</\\w+>");

    //Light checking
    if (string.IsNullOrEmpty(xmlString) || tagsWithData.IsMatch(xmlString) == false)
    {
        return false;
    }

    try
    {
        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.LoadXml(xmlString);
        return true;
    }
    catch (Exception e1)
    {
        return false;
    }
}

[TestMethod()]
public void TestValidXml()
{
    string xml = "<result>true</result>";
    Assert.IsTrue(Utility.IsValidXml(xml));
}

[TestMethod()]
public void TestIsNotValidXml()
{
    string json = "{ \"result\": \"true\" }";
    Assert.IsFalse(Utility.IsValidXml(json));
}

【讨论】:

    【解决方案3】:

    这是一种合理的方法,除了 IsNullOrEmpty 是多余的(LoadXml 可以很好地解决这个问题)。如果您确实保留 IsNullOrEmpty,请执行 if(!string.IsNullOrEmpty(value))。

    不过,基本上,问题在于您的调试器,而不是代码。

    【讨论】:

    • 我已经同意了。我已经使用调试器属性 [DebuggerStepThrough] 标记了该方法,该属性会停止调试器在异常时停止。
    • IsNullOrEmpty 只是一种优化,可以避免调用 IsValidXml("") 时的异常开销——这在我的程序中经常发生。
    【解决方案4】:

    [System.Diagnostics.DebuggerStepThrough] 属性添加到IsValidXml 方法。这会抑制 XmlException 被调试器捕获,这意味着您可以打开对首次更改异常的捕获,并且不会调试此特定方法。

    【讨论】:

      【解决方案5】:

      使用XmlDocument 时要小心,因为可以使用&lt;0&gt;some text&lt;/0&gt; 加载元素 XmlDocument doc = (XmlDocument)JsonConvert.DeserializeXmlNode(object) 没有抛出异常。

      数字元素名称不是有效的 xml,在我的情况下,直到我尝试将 xmlDoc.innerText 写入 xml 的 Sql 服务器数据类型时才发生错误。

      这就是我现在验证的方式,然后抛出异常
      XmlDocument tempDoc = XmlDocument)JsonConvert.DeserializeXmlNode(formData.ToString(), "data"); doc.LoadXml(tempDoc.InnerXml);

      【讨论】:

      • 好点 - xml 标准说 '后跟零个或多个名称字符 -- [4] NameChar ::= Letter |数字 | '。' | '-' | '' | ':' |组合字符 |扩展器 [5] 名称 ::= (字母 | '' | ':') (NameChar)*
      【解决方案6】:

      XmlTextReader 类是一个 XmlReader 的实现,以及 提供快速、高性能的解析器。它 强制执行 XML 必须遵守的规则 格式良好。它既不是一个 验证或非验证解析器 因为它没有 DTD 或模式 信息。它可以读取文本 块,或从 流。

      还有一个来自另一篇 MSDN 文章的示例,我在其中添加了代码以供阅读 XML 流的全部内容。

      string str = "<ROOT>AQID</ROOT>";
      XmlTextReader r = new XmlTextReader(new StringReader(str));
      try
      {
        while (r.Read())
        {
        }
      }
      finally
      {
        r.Close();
      }
      

      来源:http://bytes.com/topic/c-sharp/answers/261090-check-wellformedness-xml

      【讨论】:

        【解决方案7】:

        我不同意问题出在调试器上。一般来说,对于非异常情况,应该避免异常。这意味着如果有人正在寻找像 IsWellFormed() 这样的方法,它根据输入是否是格式良好的 XML 返回 true/false,则不应在此实现中抛出异常,无论它们是否被捕获和处理.

        异常代价高昂,在正常成功执行期间不应遇到。一个例子是编写一个检查文件是否存在的方法,并使用 File.Open 并在文件不存在的情况下捕获异常。这将是一个糟糕的实现。相反,应该使用File.Exists()(希望它的实现不会简单地在某个方法周围放置一个try/catch,如果文件不存在则会引发异常,我敢肯定它不存在)。

        【讨论】:

        • 我不确定这个答案是否有帮助。您还没有提供另一种方法来检查不会引发异常的格式正确。这似乎是关于您对引发异常的方法的看法的陈述。
        • Steve 明确要求提供一种不使用 try-catch 的方法,因此告诉他应该在不使用 try-catch 的情况下执行此操作确实没有帮助,而且近乎讽刺。
        • 我并没有试图讽刺,我知道我没有回答这个问题。我想这很明显。我在评论其他cmets。我想我应该将我的回复作为评论添加到我正在评论的回复中。
        【解决方案8】:

        只是我的 2 美分 - 关于这个问题有各种各样的问题,大多数人都同意“垃圾进 - 垃圾出”的事实。我不同意这一点 - 但我个人发现了以下快速而肮脏的解决方案,特别是在您处理来自 3rd 方的 xml 数据的情况下,这些数据根本无法与您轻松沟通。它不会避免使用 try/ catch - 但它以更精细的粒度使用它,因此在无效 xml 字符的数量不是那么大的情况下,它会有所帮助.. 我使用 XmlTextReader,它的方法 ReadChars() 用于每个父元素,这是命令之一不做格式良好的检查,就像 ReadInner/OuterXml 做的那样。因此,当 Read() 遇到父节点时,它是 Read() 和 ReadChars() 的组合。当然这是可行的,因为我可以假设 XML 的基本结构是好的,但是某些节点的内容(值)可以包含没有被 &.. 替换的特殊字符;等效...(我在某处找到了有关此的文章,但目前找不到源链接)

        【讨论】:

          【解决方案9】:

          我正在使用这个函数来验证字符串/片段

          <Runtime.CompilerServices.Extension()>
          Public Function IsValidXMLFragment(ByVal xmlFragment As String, Optional Strict As Boolean = False) As Boolean
              IsValidXMLFragment = True
          
              Dim NameTable As New Xml.NameTable
          
              Dim XmlNamespaceManager As New Xml.XmlNamespaceManager(NameTable)
              XmlNamespaceManager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema")
              XmlNamespaceManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
          
              Dim XmlParserContext As New Xml.XmlParserContext(Nothing, XmlNamespaceManager, Nothing, Xml.XmlSpace.None)
          
              Dim XmlReaderSettings As New Xml.XmlReaderSettings
              XmlReaderSettings.ConformanceLevel = Xml.ConformanceLevel.Fragment
              XmlReaderSettings.ValidationType = Xml.ValidationType.Schema
              If Strict Then
                  XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.ProcessInlineSchema)
                  XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.ReportValidationWarnings)
              Else
                  XmlReaderSettings.ValidationFlags = XmlSchemaValidationFlags.None
                  XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.AllowXmlAttributes)
              End If
          
              AddHandler XmlReaderSettings.ValidationEventHandler, Sub() IsValidXMLFragment = False
              AddHandler XmlReaderSettings.ValidationEventHandler, AddressOf XMLValidationCallBack
          
              Dim XmlReader As Xml.XmlReader = Xml.XmlReader.Create(New IO.StringReader(xmlFragment), XmlReaderSettings, XmlParserContext)
              While XmlReader.Read
                  'Read entire XML
              End While
          End Function
          

          我正在使用此功能来验证文件:

          Public Function IsValidXMLDocument(ByVal Path As String, Optional Strict As Boolean = False) As Boolean
              IsValidXMLDocument = IO.File.Exists(Path)
              If Not IsValidXMLDocument Then Exit Function
          
              Dim XmlReaderSettings As New Xml.XmlReaderSettings
              XmlReaderSettings.ConformanceLevel = Xml.ConformanceLevel.Document
              XmlReaderSettings.ValidationType = Xml.ValidationType.Schema
              If Strict Then
                  XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.ProcessInlineSchema)
                  XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.ReportValidationWarnings)
              Else
                  XmlReaderSettings.ValidationFlags = XmlSchemaValidationFlags.None
                  XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.AllowXmlAttributes)
              End If
              XmlReaderSettings.CloseInput = True
          
              AddHandler XmlReaderSettings.ValidationEventHandler, Sub() IsValidXMLDocument = False
              AddHandler XmlReaderSettings.ValidationEventHandler, AddressOf XMLValidationCallBack
          
              Using FileStream As New IO.FileStream(Path, IO.FileMode.Open)
                  Using XmlReader As Xml.XmlReader = Xml.XmlReader.Create(FileStream, XmlReaderSettings)
                      While XmlReader.Read
                          'Read entire XML
                      End While
                  End Using
              End Using
          End Function
          

          【讨论】:

            【解决方案10】:

            另外,当只验证 XML 字符串的语法正确性时(当不需要解析外部模式时),我认为添加 XmlResolver = null 设置可能是个好主意。这既确保了安全性(无 Web 访问)和安全性(避免恶意 XML 内容引导代码访问不良站点)。代码如下(需要 C# 2.0 或更高版本):

            public static bool IsValidXml(string candidateString)
            {
                try
                {
                    XmlReaderSettings settings = new XmlReaderSettings();
                    settings.XmlResolver = null;
                    XmlDocument document = new XmlDocument();
                    document.XmlResolver = null;
                    document.Load(XmlReader.Create(new MemoryStream(Encoding.UTF8.GetBytes(candidateString)), settings));
                    return true;
                }
                catch (XmlException)
                {
                    return false;
                }
            }
            

            针对 C# 6.0 或更高版本的优化版本:

            public static bool IsValidXml(string candidateString)
            {
                try
                {
                    var settings = new XmlReaderSettings { XmlResolver = null };
                    var document = new XmlDocument() { XmlResolver = null };
                    document.Load(XmlReader.Create(new MemoryStream(Encoding.UTF8.GetBytes(candidateString)), settings));
                    return true;
                }
                catch (XmlException)
                {
                    return false;
                }
            }
            

            【讨论】:

              【解决方案11】:

              我的两分钱。这很简单,并且遵循一些常见的约定,因为它是关于解析的......

              public bool TryParse(string s, ref XmlDocument result)
              {
                  try {
                      result = new XmlDocument();
                      result.LoadXml(s);
                      return true;
                  } catch (XmlException ex) {
                      return false;
                  }
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2018-07-03
                • 1970-01-01
                • 2012-10-24
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多