小さな (2 ~ 10 KB) XML ドキュメントを入力として WCF サービスに渡しています。受信 XML からデータ値を読み取るための 2 つのオプションがあります。
- 厳密に型指定されたオブジェクトに逆シリアル化し、オブジェクト プロパティを使用して値にアクセスする
- XPath を使用して値にアクセスする
どちらのアプローチが速いですか?あなたの答えを裏付けるいくつかの統計は素晴らしいでしょう。
小さな (2 ~ 10 KB) XML ドキュメントを入力として WCF サービスに渡しています。受信 XML からデータ値を読み取るための 2 つのオプションがあります。
どちらのアプローチが速いですか?あなたの答えを裏付けるいくつかの統計は素晴らしいでしょう。
私はそれを逆シリアル化します。
xpath を使用する場合は、XmlDocument などに逆シリアル化 (または「ロード」) します。したがって、両方のソリューションで時間の逆シリアル化が使用されます。これが完了すると、その文字列の解析、名前の解決、関数の実行などに時間がかかるため、xpath は遅くなります。また、xpath を使用すると、タイプ セーフが得られません。コンパイラは xpath 構文をチェックできません。
XmlSerializer とクラスを使用すると、静的型付けが得られます。データへのアクセスは非常に高速で、xpath を使用してクエリを実行したい場合は、それを行う方法がまだあります。
また、クラスを使用すると、コードが理解しやすくなると思います。
唯一の欠点は、xml が常に同じスキーマに準拠する必要があることですが、それは実際の問題ではないかもしれません。
統計がないことをご容赦ください。例がなくても、議論は十分に強力だと思います。究極の答えが必要な場合は、両方を試して、ストップウォッチを用意してください。
XML に固執する 3 番目のオプションがありますが、使用している 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
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);
}
初回: 247024
1000 読み取り平均: 113