在没有try / catch的情况下检查格式良好的XML?

时间:2009-06-22 09:21:54

标签: c# xml well-formed

有没有人知道如何检查字符串是否包含格式良好的XML而不在try / catch块中使用XmlDocument.LoadXml()之类的东西?我有输入可能是也可能不是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。异常是在调试期间导致快乐的地狱,因为每次我检查一个字符串调试器都会在这里打破,“帮助”我解决我的麻烦问题。

11 个答案:

答案 0 :(得分:23)

我不知道如何在没有例外的情况下进行验证,但您可以将调试器设置更改为仅在XmlException处理时如果未处理 - 这应解决您的即时问题,即使代码仍然不优雅

要执行此操作,请转到Debug / Exceptions ... / Common Language Runtime Exceptions并找到System.Xml.XmlException,然后确保仅选中“User-unhandled”(不是Thrown)。

答案 1 :(得分:7)

史蒂夫,

我们有一个第三方偶然发送了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));
}

答案 2 :(得分:5)

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

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

答案 3 :(得分:4)

[System.Diagnostics.DebuggerStepThrough]属性添加到IsValidXml方法。这样可以防止调试器捕获XmlException,这意味着您可以启用捕获首次更改的异常,并且不会调试此特定方法。

答案 4 :(得分:2)

谨慎使用XmlDocument可以使用<0>some text</0>加载元素 XmlDocument doc = (XmlDocument)JsonConvert.DeserializeXmlNode(object) 没有抛出异常。

数字元素名称无效xml,在我的情况下,在我尝试将xmlDoc.innerText写入xml的Sql server数据类型之前,没有发生错误。

我现在如何验证,并抛出异常 XmlDocument tempDoc = XmlDocument)JsonConvert.DeserializeXmlNode(formData.ToString(), "data"); doc.LoadXml(tempDoc.InnerXml);

答案 5 :(得分: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

答案 6 :(得分:0)

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

异常是昂贵的,在正常成功执行期间不应该遇到它们。一个例子是编写一个方法来检查文件的存在并使用File.Open并在文件不存在的情况下捕获异常。这将是一个糟糕的实施。相反应该使用File.Exists()(并且希望实现它不会简单地将try / catch放在一个抛出异常的方法中,如果文件不存在,我相信它不会。) / p>

答案 7 :(得分:0)

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

答案 8 :(得分: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

答案 9 :(得分: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;
    }
}

答案 10 :(得分:-2)

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

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