27

有谁知道如何XmlDocument.LoadXml()在不使用 try/catch 块中的内容的情况下检查字符串是否包含格式正确的 XML?我的输入可能是 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。该异常在调试过程中引起了快乐的地狱,因为每次我检查一个字符串时,调试器都会在这里中断,“帮助”我解决我讨厌的问题。

4

11 回答 11

23

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

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

于 2009-06-22T09:27:00.530 回答
8

史蒂夫,

我们有一个第 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));
}
于 2013-04-05T13:29:32.497 回答
6

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

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

于 2009-06-22T09:28:05.100 回答
4

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

于 2010-09-22T09:40:12.747 回答
2

小心使用XmlDocument,因为它可以沿着<0>some text</0>使用 的线加载元素XmlDocument doc = (XmlDocument)JsonConvert.DeserializeXmlNode(object) 而不会引发异常。

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

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

于 2015-11-08T21:17:00.787 回答
1

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

于 2011-03-22T06:57:42.237 回答
0

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

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

于 2012-10-23T17:31:24.463 回答
0

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

于 2013-06-01T13:03:42.567 回答
0

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

<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
于 2019-10-15T21:02:26.600 回答
0

另外,当只验证 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;
    }
}
于 2019-11-08T10:40:24.550 回答
-2

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

public bool TryParse(string s, ref XmlDocument result)
{
    try {
        result = new XmlDocument();
        result.LoadXml(s);
        return true;
    } catch (XmlException ex) {
        return false;
    }
}
于 2015-01-23T18:47:17.350 回答