厳密に型指定された拡張のサンプル
このサンプルでは、例を示す目的で SyndicationFeed クラスを使用します。ただし、このサンプルで示すパターンは、拡張データをサポートするすべての配信クラスで使用できます。
メモ : |
---|
このサンプルをビルドして実行するには、.NET Framework Version 3.5 をインストールする必要があります。Visual Studio 2008 では、プロジェクトとソリューション ファイルを開く必要があります。 |
配信オブジェクト モデル (SyndicationFeed、SyndicationItem、および関連クラス) は、AttributeExtensions プロパティおよび ElementExtensions プロパティを使用することにより、拡張データへの弱い型定義によるアクセスをサポートします。このサンプルでは、特定のアプリケーション固有の拡張を型を厳密に指定したプロパティとして公開する SyndicationFeed および SyndicationItem のカスタム派生クラスを実装することにより、拡張データへの型を厳密に指定したアクセスを提供する方法を示します。
例として、このサンプルでは Atom Threading Extensions の RFC 案で定義された拡張要素を実装する方法を示しています。このサンプルは、使い方を示すために用意されたものであり、仕様案を完全に実装するためのものではありません。
サンプル XML
次の XML スニペットは、in-reply-to 拡張要素が追加された Atom 1.0 エントリを示しています。
<entry>
<id>tag:example.org,2005:1,2</id>
<title type="text">Another response to the original</title>
<summary type="text">
This is a response to the original entry</summary>
<updated>2006-03-01T12:12:13Z</updated>
<link href="http://www.example.org/entries/1/2" />
<in-reply-to p3:ref="tag:example.org,2005:1"
p3:href="http://www.example.org/entries/1"
p3:type="application/xhtml+xml"
xmlns:p3="http://purl.org/syndication/thread/1.0"
xmlns="http://purl.org/syndication/thread/1.0">
<anotherElement xmlns="http://www.w3.org/2005/Atom">
Some more data</anotherElement>
<aDifferentElement xmlns="http://www.w3.org/2005/Atom">
Even more data</aDifferentElement>
</in-reply-to>
</entry>
<in-reply-to>
要素は、3 つの必須の属性 (ref、 type、および href) を指定しますが、追加の拡張属性および拡張要素が存在することもできます。
In-Reply-To 要素のモデル化
このサンプルでは、<in-reply-to>
要素は IXmlSerializable を実装する CLR としてモデル化されており、DataContractSerializer と共に使用することが可能です。さらに、次のサンプル コードに示すように、要素のデータにアクセスするメソッドおよびプロパティも実装しています。
[XmlRoot(ElementName = "in-reply-to", Namespace = "http://purl.org/syndication/thread/1.0")]
public class InReplyToElement : IXmlSerializable
{
internal const string ElementName = "in-reply-to";
internal const string NsUri =
"http://purl.org/syndication/thread/1.0";
private Dictionary<XmlQualifiedName, string> extensionAttributes;
private Collection<XElement> extensionElements;
public InReplyToElement()
{
this.extensionElements = new Collection<XElement>();
this.extensionAttributes = new Dictionary<XmlQualifiedName,
string>();
}
public Dictionary<XmlQualifiedName, string> AttributeExtensions
{
get { return this.extensionAttributes; }
}
public Collection<XElement> ElementExtensions
{
get { return this.extensionElements; }
}
public Uri Href
{ get; set; }
public string MediaType
{ get; set; }
public string Ref
{ get; set; }
public Uri Source
{ get; set; }
}
InReplyToElement
クラスは、必須の属性 (HRef、MediaType、および Source) のプロパティと共に、AttributeExtensions および ElementExtensions を保持するコレクションを実装します。
InReplyToElement
クラスは、IXmlSerializable インターフェイスを実装します。このインターフェイスは、オブジェクト インスタンスを XML から読み取る、または書き込む方法の直接制御を可能にします。ReadXml
メソッドは、渡された XmlReader から Ref、HRef、Source、および MediaType の各プロパティを最初に読み取ります。不明な属性はAttributeExtensions コレクションに格納されます。すべての属性が読み取られると、ReadStartElement が呼び出されて、リーダーが次の要素に進みます。このクラスによりモデル化された要素には必要な子がないため、子要素は XElement インスタンスにバッファされ、ElementExtensions コレクションに格納されます。
public void ReadXml(System.Xml.XmlReader reader)
{
bool isEmpty = reader.IsEmptyElement;
if (reader.HasAttributes)
{
for (int i = 0; i < reader.AttributeCount; i++)
{
reader.MoveToNextAttribute();
if (reader.NamespaceURI == "")
{
if (reader.LocalName == "ref")
{
this.Ref = reader.Value;
}
else if (reader.LocalName == "href")
{
this.Href = new Uri(reader.Value);
}
else if (reader.LocalName == "source")
{
this.Source = new Uri(reader.Value);
}
else if (reader.LocalName == "type")
{
this.MediaType = reader.Value;
}
else
{
this.AttributeExtensions.Add(new
XmlQualifiedName(reader.LocalName,
reader.NamespaceURI),
reader.Value);
}
}
}
}
reader.ReadStartElement();
if (!isEmpty)
{
while (reader.IsStartElement())
{
ElementExtensions.Add(
(XElement) XElement.ReadFrom(reader));
}
reader.ReadEndElement();
}
}
WriteXml
では、InReplyToElement
メソッドは最初に Ref、HRef、Source、および MediaType の各プロパティの値を XML 属性として書き込みます (WriteXml
は、実際の外側の要素自体は書き込みません。WriteXml
により行われるためです)。さらに、AttributeExtensions および ElementExtensions の内容をライタに書き込みます。
public void WriteXml(System.Xml.XmlWriter writer)
{
if (this.Ref != null)
{
writer.WriteAttributeString("ref", InReplyToElement.NsUri,
this.Ref);
}
if (this.Href != null)
{
writer.WriteAttributeString("href", InReplyToElement.NsUri,
this.Href.ToString());
}
if (this.Source != null)
{
writer.WriteAttributeString("source", InReplyToElement.NsUri,
this.Source.ToString());
}
if (this.MediaType != null)
{
writer.WriteAttributeString("type", InReplyToElement.NsUri,
this.MediaType);
}
foreach (KeyValuePair<XmlQualifiedName, string> kvp in
this.AttributeExtensions)
{
writer.WriteAttributeString(kvp.Key.Name, kvp.Key.Namespace,
kvp.Value);
}
foreach (XElement element in this.ElementExtensions)
{
element.WriteTo(writer);
}
}
ThreadedFeed および ThreadedItem
このサンプルでは、InReplyTo
拡張が存在する SyndicationItems
が ThreadedItem
クラスによりモデル化されます。同様に、ThreadedFeed
クラスは、項目が ThreadedItem
のすべてのインスタンスである SyndicationFeed です。
ThreadedFeed
クラスは、SyndicationFeed から継承され、OnCreateItem をオーバーライドして ThreadedItem
を返します。さらに、Items
コレクションにアクセスするメソッドを ThreadedItems
として実装します。
public class ThreadedFeed : SyndicationFeed
{
public ThreadedFeed()
{
}
public IEnumerable<ThreadedItem> ThreadedItems
{
get
{
return this.Items.Cast<ThreadedItem>();
}
}
protected override SyndicationItem CreateItem()
{
return new ThreadedItem();
}
}
ThreadedItem
クラスは SyndicationItem から継承され、InReplyToElement
を厳密に型指定されたプロパティとします。これにより、InReplyTo
拡張データにプログラムによって簡単にアクセスできます。さらに、その拡張データの読み取り/書き込みを行う TryParseElement
および WriteElementExtensions
も実装します。
public class ThreadedItem : SyndicationItem
{
private InReplyToElement inReplyTo;
// Constructors
public ThreadedItem()
{
inReplyTo = new InReplyToElement();
}
public ThreadedItem(string title, string content, Uri itemAlternateLink, string id, DateTimeOffset lastUpdatedTime) : base(title, content, itemAlternateLink, id, lastUpdatedTime)
{
inReplyTo = new InReplyToElement();
}
public InReplyToElement InReplyTo
{
get { return this.inReplyTo; }
}
protected override bool TryParseElement(
System.Xml.XmlReader reader,
string version)
{
if (version == SyndicationVersions.Atom10 &&
reader.NamespaceURI == InReplyToElement.NsUri &&
reader.LocalName == InReplyToElement.ElementName)
{
this.inReplyTo = new InReplyToElement();
this.InReplyTo.ReadXml(reader);
return true;
}
else
{
return base.TryParseElement(reader, version);
}
}
protected override void WriteElementExtensions(XmlWriter writer,
string version)
{
if (this.InReplyTo != null &&
version == SyndicationVersions.Atom10)
{
writer.WriteStartElement(InReplyToElement.ElementName,
InReplyToElement.NsUri);
this.InReplyTo.WriteXml(writer);
writer.WriteEndElement();
}
base.WriteElementExtensions(writer, version);
}
}
サンプルを設定、ビルド、および実行するには
「Windows Communication Foundation サンプルの 1 回限りのセットアップの手順」が実行済みであることを確認します。
ソリューションの C# 版または Visual Basic .NET 版をビルドするには、「Windows Communication Foundation サンプルのビルド」の手順を参照してください。
単一コンピュータ構成か複数コンピュータ構成かに応じて、「Windows Communication Foundation サンプルの実行」の手順に従います。
Copyright © 2007 by Microsoft Corporation.All rights reserved.