簡體   English   中英

不用 try/catch 檢查格式正確的 XML?

[英]Check well-formed XML without a try/catch?

有誰知道如何在 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;
        }
    }

但似乎不需要 try/catch 的東西。 異常在調試過程中會導致歡樂地獄,因為每次我檢查一個字符串時,調試器都會在這里中斷,“幫助”我解決我討厭的問題。

我不知道沒有異常的驗證方法,但是您可以將調試器設置更改為僅在未處理的情況下為XmlException中斷 - 這應該可以解決您的直接問題,即使代碼仍然不夠優雅。

為此,請轉到 Debug / Exceptions... / Common Language Runtime Exceptions 並找到 System.Xml.XmlException,然后確保只勾選了“User-unhandled”(未拋出)。

史蒂夫,

我們有一個 3rd 方有時會不小心向我們發送 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));
}

這是一個合理的方法,除了 IsNullOrEmpty 是多余的(LoadXml 可以很好地解決這個問題)。 如果您確實保留 IsNullOrEmpty,請執行 if(!string.IsNullOrEmpty(value))。

但是,基本上,您的調試器是問題所在,而不是代碼。

[System.Diagnostics.DebuggerStepThrough]屬性添加到IsValidXml方法。 這會抑制 XmlException 被調試器捕獲,這意味着您可以打開對首次更改異常的捕獲,並且不會調試此特定方法。

使用XmlDocument要小心,因為它可能會使用XmlDocument doc = (XmlDocument)JsonConvert.DeserializeXmlNode(object)沿着<0>some text</0>的行加載元素不會引發異常。

數字元素名稱不是有效的 xml,在我的情況下,直到我嘗試將 xmlDoc.innerText 寫入 Sql 服務器數據類型 xml 時才發生錯誤。

這就是我現在驗證的方式,並拋出異常
XmlDocument tempDoc = XmlDocument)JsonConvert.DeserializeXmlNode(formData.ToString(), "data"); doc.LoadXml(tempDoc.InnerXml);

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

我不同意問題出在調試器上。 一般來說,對於非異常情況,應該避免異常。 這意味着,如果有人正在尋找像IsWellFormed()這樣的方法,該方法根據輸入是否為格式良好的 XML 返回真/假,則不應在此實現中拋出異常,無論它們是否被捕獲和處理.

異常代價高昂,在正常的成功執行過程中不應遇到異常。 一個例子是編寫一個方法來檢查文件是否存在並使用 File.Open 並在文件不存在的情況下捕獲異常。 這將是一個糟糕的實施。 相反,應該使用File.Exists() (並且希望它的實現不會簡單地將 try/catch 放在一些方法周圍,如果文件不存在則拋出異常,我確定它不存在)。

只是我的 2 美分 - 關於這個有各種各樣的問題,大多數人都同意“垃圾進 - 垃圾出”的事實。 我並不反對這一點 - 但我個人發現了以下快速而骯臟的解決方案,特別是對於您處理來自 3rd 方的 xml 數據的情況,這些數據根本無法與您輕松溝通..它不會避免使用 try/ catch - 但它以更細的粒度使用它,所以在無效 xml 字符的數量不是那么大的情況下,它有幫助..我使用了 XmlTextReader 及其每個父元素的 ReadChars() 方法,這是命令之一不做格式良好的檢查,就像 ReadInner/OuterXml 那樣。 因此,當 Read() 在父節點上存根時,它是 Read() 和 ReadChars() 的組合。 當然這是有效的,因為我可以假設 XML 的基本結構沒問題,但是某些節點的內容(值)可以包含尚未用 &..; 替換的特殊字符。 等效...(我在某處找到了一篇關於此的文章,但目前找不到源鏈接)

我正在使用以下功能處理文檔/片段

<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

    AddHandler XmlReaderSettings.ValidationEventHandler, Sub() IsValidXMLDocument = False
    AddHandler XmlReaderSettings.ValidationEventHandler, AddressOf XMLValidationCallBack

    Dim FileStream As New IO.FileStream(Path, IO.FileMode.Open)
    Dim XmlReader As Xml.XmlReader = Xml.XmlReader.Create(FileStream, XmlReaderSettings)
    While XmlReader.Read
        'Read entire XML
    End While
End Function

我正在使用此函數來驗證字符串/片段

<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

另外,當只驗證XML字符串的語法正確性時(不需要解析外部schema時),我認為添加一個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;
    }
}

我的兩分錢。 這非常簡單,並且遵循一些常見的約定,因為它是關於解析...

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM