我将小(2-10 KB)XML 文档作为输入传递给 WCF 服务。现在我有两个选项可以从传入的 XML 中读取数据值
- 反序列化为强类型对象并使用对象属性访问值
- 使用 XPath 访问值
哪种方法更快?一些支持您的答案的统计数据会很棒。
我将小(2-10 KB)XML 文档作为输入传递给 WCF 服务。现在我有两个选项可以从传入的 XML 中读取数据值
哪种方法更快?一些支持您的答案的统计数据会很棒。
我会反序列化它。
如果您使用 xpath,您将反序列化(或“加载”)它到 XmlDocument 或其他东西。所以这两种解决方案都使用时间反序列化。完成此操作后,xpath 将变慢,因为解析该字符串、解析名称、执行函数等所花费的时间。此外,如果您使用 xpath,则不会获得类型安全。您的编译器无法为您检查 xpath 语法。
如果您使用 XmlSerializer 和类,您将获得静态类型。真正快速地访问您的数据,如果您想使用 xpath 查询它们,仍然有办法做到这一点。
另外,我想说你的代码可能会更容易理解类。
唯一的缺点是 xml 必须始终符合相同的模式,但这在您的情况下可能不是真正的问题。
我希望你原谅没有统计数据,我认为没有例子的论点就足够了。如果您想要最终答案,请尝试两者并准备好秒表。
还有第三种坚持使用 XML 的选项,但是使用您正在使用的任何 XML API 进行查询——例如 LINQ to XML 使得查询在代码中相对简单。
您是否已经将文本解析为 XML 文档?
您是否确信这实际上是您代码中的一个重要性能瓶颈?(例如,如果您正在与数据库交谈,那么开始时不要担心 - 先让它以最简单的方式工作)
查询总是相同的,还是以某种方式动态?
您是否有带有真实消息和查询的测试平台?如果没有,您需要使用您的数据来评估此处给出的任何答案。如果你这样做了,我希望你自己尝试一下会相当容易:)
这里有 4 个案例,所有时间都在刻度和位置:
样本对象被读取 1000 次。
你应该关心吗?在大多数情况下,使用 .net 中内置的默认序列化程序。没有必要偏离,这将产生最少的代码。这些应该绰绰有余,提供类型安全并让自己腾出时间做更有意义的事情。在某些情况下,如果您希望从大型 XML 结构中挑选某些数据元素,XElement 可能会很有用,但即便如此,也应该将这些元素放入强类型 DTO 中。但请记住,所有方法都非常快。我个人在短短几毫秒内就序列化了一个极其广泛和深入的对象模型(远超过 400 个类)。对于较小和琐碎的对象,它将是亚毫秒的响应时间。XMLSerializer 的预热比其他的要慢,但可以通过 SGEN 或在启动时进行一些初始化来缓解。
详细信息和代码...
Xml 序列化程序
[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; }
}
第一次:2448965
1000 读取平均值: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"));
}
}
}
第一次:2051813
1000 读取平均值:208
手卷
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);
}
}
第一次:161105
1000 次读取平均值:29
元素
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);
}
第一次:247024
1000 读取平均值:113