C# 检查格式良好的XML而不进行尝试/捕获?

C# 检查格式良好的XML而不进行尝试/捕获?,c#,xml,well-formed,C#,Xml,Well Formed,有人知道我如何在try/catch块中不使用类似于XmlDocument.LoadXml()的东西来检查字符串是否包含格式良好的XML吗?我得到的输入可能是XML,也可能不是XML,我希望代码能够识别输入可能不是XML,而不依赖于try/catch,无论是速度还是非异常情况不应引发异常的一般原则。我目前有这样做的代码 private bool IsValidXML(string value) { try { // Check we

有人知道我如何在try/catch块中不使用类似于
XmlDocument.LoadXml()
的东西来检查字符串是否包含格式良好的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;
        }
    }

但这似乎不需要尝试/抓住。在调试过程中,异常会导致merry hell,因为每次我检查字符串时,调试器都会在这里中断,“帮助”我解决讨厌的问题

我不知道如何在没有异常的情况下进行验证,但是如果未处理,您可以将调试器设置更改为仅中断
XmlException
,这应该可以解决您眼前的问题,即使代码仍然不雅


要执行此操作,请转到调试/异常…/公共语言运行时异常并查找System.Xml.XmlException,然后确保只勾选了“User unhandled”(未抛出)。

这是一种合理的方法,只是IsNullOrEmpty是冗余的(LoadXml可以很好地解决这个问题)。如果确实保持IsNullOrEmpty,请执行If(!string.IsNullOrEmpty(value))


但基本上,问题出在调试器上,而不是代码。

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

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();
}
string str=“AQID”;
XmlTextReader r=新的XmlTextReader(新的StringReader(str));
尝试
{
while(r.Read())
{
}
}
最后
{
r、 Close();
}


来源:

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

异常代价高昂,在正常成功执行期间不应遇到异常。例如,编写一个方法来检查文件是否存在,并使用file.Open在文件不存在的情况下捕获异常。这将是一个糟糕的实现。相反,应该使用
File.Exists()
(希望它的实现不会简单地对某个方法进行try/catch操作,如果该文件不存在,就会抛出异常,我确信它不存在)。

我们有一个第三方,它有时会意外地向我们发送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));
}
公共静态bool IsValidXml(字符串xmlString)
{

Regex tagsWithData=newregex(“[^只要我的2美分-关于这一点有各种各样的问题,大多数人都同意“垃圾输入-垃圾输出”"事实上,我并不反对这一点——但我个人发现了以下快速而肮脏的解决方案,特别是对于处理来自第三方的xml数据的情况,这些数据根本不容易与您通信……它并没有避免使用try/catch——但它使用的粒度更细,因此在无效xml字符数量减少的情况下s没有那么大,它有帮助..我使用了XmlTextReader,它的方法ReadChars()用于每个父元素,这是一个不像ReadInner/OuterXml那样进行格式良好检查的命令。因此,它是Read()和ReadChars()的组合父节点上的存根。当然,这是可行的,因为我可以假设XML的基本结构没有问题,但某些节点的内容(值)可以包含未被替换为&;等效…(我在某处找到一篇关于此的文章,但目前找不到源链接)我的2美分。这非常简单,并且遵循一些常见的约定,因为它是关于解析的

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

使用
XmlDocument
时要小心,因为可以使用
XmlDocument doc=(XmlDocument)JsonConvert.DeserializeXmlNode(对象)
,不会引发异常

数字元素名称不是有效的xml,在我的例子中,直到我尝试将xmlDoc.innerText写入Sql server数据类型xml时才发生错误

这就是我现在验证的方式,并引发异常
XmlDocument tempDoc=XmlDocument)JsonConvert.DeserializeXmlNode(formData.ToString(),“data”);

doc.LoadXml(tempDoc.InnerXml);

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

<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

此外,当只验证XML字符串的语法正确性时(无需解析外部架构),我认为添加
XmlResolver=null
设置可能是一个好主意。这既可以确保安全性(无Web访问)又可以确保安全性(避免恶意XML内容将代码定向到坏站点)。代码如下(要求C#2.0或更高):

C#6.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;
    }
}
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;
    }
}

+1用于此救生解决方案。我仅在必须调试失败的代码时启用在处理异常时中断。我同意。我已使用调试器属性[DebuggerStepThrough]标记该方法,该属性可停止调试器停止
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;
    }
}