c# - node - xpath list of elements
XPath vs DeSerialization: cuál es mejor en rendimiento para operaciones de lectura (3)
Hay una tercera opción de seguir con XML, pero consulte con cualquier API XML que esté utilizando, por ejemplo, LINQ to XML hace que las consultas sean relativamente sencillas en el código.
¿Ya has analizado el texto en un documento XML?
¿Estás convencido de que esto es realmente un cuello de botella de rendimiento significativo en tu código? (por ejemplo, si estás hablando con una base de datos, entonces no te preocupes por esto para empezar, simplemente haz que funcione de la manera más simple)
¿Las consultas son siempre las mismas o son dinámicas de alguna manera?
¿Tiene una plataforma de prueba con mensajes realistas y consultas? Si no, necesita uno para evaluar las respuestas dadas aquí con sus datos. Si lo hace, yo esperaría que sea razonablemente fácil probarlo usted mismo :)
Estoy pasando documentos XML pequeños (2-10 KB) como entrada a un servicio WCF. ahora tengo dos opciones para leer valores de datos del XML entrante
- Deserializar a un objeto fuertemente tipado y usar propiedades de objeto para acceder a los valores
- usa XPath para acceder a los valores
qué enfoque es más rápido? algunas estadísticas para apoyar su respuesta serían geniales.
Yo lo deserializaría.
Si usa xpath, lo deserializará (o "cargará") a XmlDocument o algo de todos modos. Entonces, ambas soluciones usan deserialización de tiempo. Una vez hecho esto, xpath será más lento debido al tiempo dedicado al análisis de esa cadena, a la resolución de nombres, a la ejecución de funciones, etc. Además, si vas con xpath, no obtienes ningún tipo de seguridad. Su compilador no puede verificar la sintaxis xpath por usted.
Si usa XmlSerializer y clases, obtiene tipeo estático. Acceso realmente rápido a sus datos, y si desea consultarlos con xpath, todavía hay maneras de hacerlo.
Además, me gustaría decir que su código probablemente sería más fácil de entender con las clases.
El único inconveniente es que el xml debe ajustarse al mismo esquema todo el tiempo, pero eso podría no ser un problema real en su caso.
Espero que perdonen la ausencia de estadísticas, creo que los argumentos son lo suficientemente sólidos sin ejemplos. Si quieres una respuesta definitiva, prueba ambos y ten un cronómetro listo.
Aquí hay 4 casos, todos los tiempos en ticks y colocación:
- XmlSerializer (4to más lento)
- Implementación de IXmlSerializable (3ra)
- Mano rodada (personalizada) (1ra)
- XElement (2nd)
El objeto de muestra fue leído 1000 veces.
¿Deberías importarte? Para la mayoría de los casos, use los serializadores predeterminados que están incorporados en .net. No hay necesidad de desviarse y eso producirá la cantidad mínima de código. Esos deberían ser más que suficientes, ofrecer seguridad tipo y liberarse para hacer cosas más significativas con su tiempo. En algunos casos, XElement puede ser útil si desea seleccionar ciertos elementos de datos de una estructura XML grande, pero aun así uno debe poner esos elementos en una DTO fuertemente tipada. Pero tenga en cuenta que todos los métodos son muy rápidos. He serializado personalmente un modelo de objetos extremadamente amplio y profundo (más de 400 clases) en solo unos pocos milisegundos. Para objetos más pequeños y triviales, serán tiempos de respuesta menores. El calentamiento de XMLSerializer es más lento que los demás, pero se puede mitigar con SGEN o hacer alguna inicialización al inicio.
Detalles y código ...
Xml Serializer
[Serializable]
public class FoobarXml
{
public string Name { get; set; }
public int Age { get; set; }
public bool IsContent { get; set; }
[XmlElement(DataType = "date")]
public DateTime BirthDay { get; set; }
}
Primera vez: 2448965
1000 promedio de lectura: 245
IXmlSerializable
public class FoobarIXml : IXmlSerializable
{
public string Name { get; set; }
public int Age { get; set; }
public bool IsContent { get; set; }
public DateTime BirthDay { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
reader.MoveToContent();
var isEmptyElement = reader.IsEmptyElement;
reader.ReadStartElement();
if (!isEmptyElement)
{
Name = reader.ReadElementString("Name");
int intResult;
var success = int.TryParse(reader.ReadElementString("Age"), out intResult);
if (success)
{
Age = intResult;
}
bool boolResult;
success = bool.TryParse(reader.ReadElementString("IsContent"), out boolResult);
if (success)
{
IsContent = boolResult;
}
DateTime dateTimeResult;
success = DateTime.TryParseExact(reader.ReadElementString("BirthDay"), "yyyy-MM-dd", null,
DateTimeStyles.None, out dateTimeResult);
if (success)
{
BirthDay = dateTimeResult;
}
reader.ReadEndElement(); //Must Do
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("Name", Name);
writer.WriteElementString("Age", Age.ToString());
writer.WriteElementString("IsContent", IsContent.ToString());
writer.WriteElementString("BirthDay", BirthDay.ToString("yyyy-MM-dd"));
}
}
}
Primera vez: 2051813
1000 promedio de lectura: 208
Laminado a mano
public class FoobarHandRolled
{
public FoobarHandRolled(string name, int age, bool isContent, DateTime birthDay)
{
Name = name;
Age = age;
IsContent = isContent;
BirthDay = birthDay;
}
public FoobarHandRolled(string xml)
{
if (string.IsNullOrWhiteSpace(xml))
{
return;
}
SetName(xml);
SetAge(xml);
SetIsContent(xml);
SetBirthday(xml);
}
public string Name { get; set; }
public int Age { get; set; }
public bool IsContent { get; set; }
public DateTime BirthDay { get; set; }
/// <summary>
/// Takes this object and creates an XML representation.
/// </summary>
/// <returns>An XML string that represents this object.</returns>
public override string ToString()
{
var builder = new StringBuilder();
builder.Append("<FoobarHandRolled>");
if (!string.IsNullOrWhiteSpace(Name))
{
builder.Append("<Name>" + Name + "</Name>");
}
builder.Append("<Age>" + Age + "</Age>");
builder.Append("<IsContent>" + IsContent + "</IsContent>");
builder.Append("<BirthDay>" + BirthDay.ToString("yyyy-MM-dd") + "</BirthDay>");
builder.Append("</FoobarHandRolled>");
return builder.ToString();
}
private void SetName(string xml)
{
Name = GetSubString(xml, "<Name>", "</Name>");
}
private void SetAge(string xml)
{
var ageString = GetSubString(xml, "<Age>", "</Age>");
int result;
var success = int.TryParse(ageString, out result);
if (success)
{
Age = result;
}
}
private void SetIsContent(string xml)
{
var isContentString = GetSubString(xml, "<IsContent>", "</IsContent>");
bool result;
var success = bool.TryParse(isContentString, out result);
if (success)
{
IsContent = result;
}
}
private void SetBirthday(string xml)
{
var dateString = GetSubString(xml, "<BirthDay>", "</BirthDay>");
DateTime result;
var success = DateTime.TryParseExact(dateString, "yyyy-MM-dd", null, DateTimeStyles.None, out result);
if (success)
{
BirthDay = result;
}
}
private string GetSubString(string xml, string startTag, string endTag)
{
var startIndex = xml.IndexOf(startTag, StringComparison.Ordinal);
if (startIndex < 0)
{
return null;
}
startIndex = startIndex + startTag.Length;
var endIndex = xml.IndexOf(endTag, StringComparison.Ordinal);
if (endIndex < 0)
{
return null;
}
return xml.Substring(startIndex, endIndex - startIndex);
}
}
Primera vez: 161105
1000 promedio de lectura: 29
XElement
var xDoc = XElement.Parse(xml);
var nameElement = xDoc.Element("Name");
var ageElement = xDoc.Element("Age");
var isContentElement = xDoc.Element("IsContent");
var birthDayElement = xDoc.Element("BirthDay");
string name = null;
if (nameElement != null)
{
name = nameElement.Value;
}
var age = 0;
if (ageElement != null)
{
age = int.Parse(ageElement.Value);
}
var isContent = false;
if (isContentElement != null)
{
isContent = bool.Parse(isContentElement.Value);
}
var birthDay = new DateTime();
if (birthDayElement != null)
{
birthDay = DateTime.ParseExact(birthDayElement.Value, "yyyy-MM-dd", CultureInfo.InvariantCulture);
}
Primera vez: 247024
1000 promedio de lectura: 113