.NET ISVALIDXML Método de extensão Desempenho
-
25-09-2019 - |
Pergunta
Eu tenho um aplicativo herdado que herdei que passa muito XML como strings.
Costumo precisar da capacidade de verificar se uma string será válida XML. Qual é a maneira mais rápida e mais barata de verificar se uma string é válida XML no .NET?
Estou trabalhando no .NET 3.5 e provavelmente o usaria como um método de extensão (fora da string) neste projeto dentro da solução.
ATUALIZAR:
O que quero dizer com "válido" no meu caso é adequadamente formado XML. Não preciso validar recursos ou esquema.
Solução
Não é possível validar a bem-formação de uma string xml sem analisá-la. E uma referência rápida mostra que a maneira mais rápida de analisar uma string para ver se é válida (na verdade, a maneira mais rápida de analisar a string específica que eu uso como um caso de teste) é com um XMLReader:
static void Main(string[] args)
{
const int iterations = 20000;
const string xml = @"<foo><bar><baz a='b' c='d'/><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo></bar><bar/></foo>";
Stopwatch st = new Stopwatch();
st.Start();
for (int i=0; i<iterations; i++)
{
using (StringReader sr = new StringReader(xml))
using (XmlReader xr = XmlReader.Create(sr))
{
while (xr.Read())
{
}
}
}
st.Stop();
Console.WriteLine(String.Format("XmlReader: {0} ms.", st.ElapsedMilliseconds));
st.Reset();
st.Start();
for (int i=0; i<iterations; i++)
{
XElement.Parse(xml);
}
st.Stop();
Console.WriteLine(String.Format("XElement: {0} ms.", st.ElapsedMilliseconds));
st.Reset();
st.Start();
for (int i = 0; i < iterations; i++)
{
XmlDocument d= new XmlDocument();
d.LoadXml(xml);
}
st.Stop();
Console.WriteLine(String.Format("XmlDocument: {0} ms.", st.ElapsedMilliseconds));
st.Reset();
st.Start();
for (int i = 0; i < iterations; i++)
{
using (StringReader sr = new StringReader(xml))
{
XPathDocument d = new XPathDocument(new StringReader(xml));
}
}
st.Stop();
Console.WriteLine(String.Format("XPathDocument: {0} ms.", st.ElapsedMilliseconds));
Console.ReadKey();
}
Na minha máquina XmlReader
é quase duas vezes mais rápido que qualquer uma das alternativas. Isso faz sentido. Embora eu não tenha usado o refletor para verificar, ficaria muito surpreso se XmlDocument
, XDocument
, e XPathDocument
não estava tudo usando XmlReader
sob o capô.
Outras dicas
Não estou ciente de uma instalação interna no .NET para validar o formado (?) De XML sem analisá-lo. Dado isso, algo assim deve funcionar:
public static class XmlUtilities
{
public static bool IsXml(this string data)
{
if (string.IsNullOrEmpty(data)) return false;
try
{
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(data);
return true;
}
catch
{
return false;
}
}
}
Concordo com Adam e a versão Xelement:
public static class XmlUtilities
{
public static bool IsXml(this string data)
{
if (string.IsNullOrEmpty(data)) return false;
try
{
var doc = XElement.Parse(data)
return true;
}
catch (XmlException)
{
return false;
}
}
}