[解決済み] XmlSerializerを使用して、空のxml属性値をnullable intプロパティにデシリアライズする。
質問
サードパーティからxmlを入手し、C#オブジェクトにデシリアライズする必要があります。このxmlは、整数型の値または空の値:attr="11 "またはattr=""を持つ属性を含む場合があります。この属性値を、nullable integer型のプロパティにデシリアライズしたい。しかし、XmlSerializerはnullable型へのデシリアライズをサポートしていません。以下のテストコードは、InvalidOperationException {"タイプ 'TestConsoleApplication.SerializeMe' を反映するエラーが発生し、XmlSerializer の作成時に失敗します。}
[XmlRoot("root")]
public class SerializeMe
{
[XmlElement("element")]
public Element Element { get; set; }
}
public class Element
{
[XmlAttribute("attr")]
public int? Value { get; set; }
}
class Program {
static void Main(string[] args) {
string xml = "<root><element attr=''>valE</element></root>";
var deserializer = new XmlSerializer(typeof(SerializeMe));
Stream xmlStream = new MemoryStream(Encoding.ASCII.GetBytes(xml));
var result = (SerializeMe)deserializer.Deserialize(xmlStream);
}
}
Value'プロパティの型をintに変更すると、InvalidOperationExceptionでデシリアライズに失敗します。
XMLドキュメントにエラーがあります(1, 16)。
空ではない属性値を整数にデシリアライズすると同時に、空の値を持つ属性をnullable型(nullとして)にデシリアライズする方法をどなたか教えていただけませんか?各フィールドのデシリアライズを手動で行う必要がないように、このためのトリックはありますか(実際には多くのフィールドがあります)?
ahsteeleからのコメント後の更新。
-
私の知る限り、この属性はXmlElementAttributeでのみ動作します - この属性は、子要素または本文のいずれであっても、要素が内容を持たないことを指定します。しかし、私はXmlAttributeAttributeのための解決策を見つける必要があります。いずれにせよ、私はxmlを変更することができないので、私はそれを制御することができません。
-
このプロパティは、属性値が空でない場合、または属性が存在しない場合にのみ機能します。attrが空の値(attr='')を持つとき、XmlSerializerコンストラクタは(予想通り)失敗します。
public class Element { [XmlAttribute("attr")] public int Value { get; set; } [XmlIgnore] public bool ValueSpecified; }
-
Alex Scordellisによるこのブログ記事のような、カスタムNullableクラス。
このブログの投稿にあるクラスを私の問題に採用することを試みました。
[XmlAttribute("attr")] public NullableInt Value { get; set; }
しかし、XmlSerializerのコンストラクタはInvalidOperationExceptionで失敗しています。
TestConsoleApplication.NullableInt型のメンバ 'Value' をシリアライズすることができません。
XmlAttribute/XmlText は IXmlSerializable } を実装した型のエンコードに使用することはできません。
-
醜いサロゲートソリューション(このコードをここで書いたことを恥じてください :) 。)
public class Element { [XmlAttribute("attr")] public string SetValue { get; set; } public int? GetValue() { if ( string.IsNullOrEmpty(SetValue) || SetValue.Trim().Length <= 0 ) return null; int result; if (int.TryParse(SetValue, out result)) return result; return null; } }
しかし、このような解決策は、私のクラスの消費者向けのインターフェイスを壊してしまうので、思いつきたくありません。IXmlSerializableインターフェイスを手動で実装したほうがよさそうです。
現在のところ、Elementクラス全体に対してIXmlSerializableを実装しなければならないようで(大きいです)、簡単な回避策はないようです...。
どのように解決するのですか?
IXmlSerializableインターフェイスを実装することで、この問題を解決しました。もっと簡単な方法はなかったのでしょうか。
以下はテストコードです。
[XmlRoot("root")]
public class DeserializeMe {
[XmlArray("elements"), XmlArrayItem("element")]
public List<Element> Element { get; set; }
}
public class Element : IXmlSerializable {
public int? Value1 { get; private set; }
public float? Value2 { get; private set; }
public void ReadXml(XmlReader reader) {
string attr1 = reader.GetAttribute("attr");
string attr2 = reader.GetAttribute("attr2");
reader.Read();
Value1 = ConvertToNullable<int>(attr1);
Value2 = ConvertToNullable<float>(attr2);
}
private static T? ConvertToNullable<T>(string inputValue) where T : struct {
if ( string.IsNullOrEmpty(inputValue) || inputValue.Trim().Length == 0 ) {
return null;
}
try {
TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
return (T)conv.ConvertFrom(inputValue);
}
catch ( NotSupportedException ) {
// The conversion cannot be performed
return null;
}
}
public XmlSchema GetSchema() { return null; }
public void WriteXml(XmlWriter writer) { throw new NotImplementedException(); }
}
class TestProgram {
public static void Main(string[] args) {
string xml = @"<root><elements><element attr='11' attr2='11.3'/><element attr='' attr2=''/></elements></root>";
XmlSerializer deserializer = new XmlSerializer(typeof(DeserializeMe));
Stream xmlStream = new MemoryStream(Encoding.ASCII.GetBytes(xml));
var result = (DeserializeMe)deserializer.Deserialize(xmlStream);
}
}
関連
-
[解決済み】プラットフォームが同じでも「不正なフォーマットでプログラムを読み込もうとしました。
-
[解決済み] AndroidでWCFサービスを利用する方法
-
[解決済み] 到達不能なホストに対してソケット操作を行おうとした
-
[解決済み] DockPanelを空きスペースいっぱいに表示させる方法
-
[解決済み] .NET WebRequestを使用してsharepointにファイルをアップロードすると、409/Conflict HTTPエラーが発生する理由?
-
[解決済み] WCFのデバッグ時にサーバーに自動的に踏み込むことができない
-
[解決済み] 埋め込みリソーステキストファイルの読み方
-
[解決済み] WCF - メッセージサイズのクォータを増加させる方法
-
[解決済み】文字列をパースしてNULL可能なint型にする方法
-
[解決済み] null可能なintをシリアライズする
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】警告。同じ依存アセンブリの異なるバージョン間で競合が見つかりました。
-
[解決済み] Microsoft.Practices.ServiceLocationはどこから来たのですか?
-
[解決済み] VB.NETでプログラムパスを取得する?
-
[解決済み] 16進数値0x00は無効な文字です。
-
[解決済み] 到達不能なホストに対してソケット操作を行おうとした
-
[解決済み] gacutil.exeはどこですか?
-
[解決済み] "SSL/TLSセキュアチャネルの信頼関係を当局と確立できませんでした "の解決方法
-
[解決済み] RelativeSourceでWPFバインディングを使用するにはどうしたらいいですか?
-
[解決済み] Visual Studioの「Any CPU」ターゲットはどういう意味ですか?
-
[解決済み] .NETで文字列から発音区分符号(アクセント)を削除するにはどうすればよいですか?