XmlSerializerでboolをyes / noとしてエンコードするにはどうすればよいですか?
-
05-07-2019 - |
質問
xmlを別のプログラムに送信します。このプログラムは、ブールフラグを「yes」と想定しています。または「true」ではなく「no」または" false"。
次のように定義されたクラスがあります:
[XmlRoot()]
public class Foo {
public bool Bar { get; set; }
}
シリアル化すると、出力は次のようになります。
<Foo><Bar>true</Bar></Foo>
しかし、これになりたい:
<Foo><Bar>yes</Bar></Foo>
シリアル化時にこれを実行できますか?これに頼る必要はありません:
[XmlRoot()]
public class Foo {
[XmlIgnore()]
public bool Bar { get; set; }
[XmlElement("Bar")]
public string BarXml { get { return (Bar) ? "yes" : "no"; } }
}
このデータを再びデシリアライズできるようにしたいことに注意してください。
解決
OK、これについてもう少し調べてきました。ここに私が思いついたものがあります:
// use this instead of a bool, and it will serialize to "yes" or "no"
// minimal example, not very robust
public struct YesNo : IXmlSerializable {
// we're just wrapping a bool
private bool Value;
// allow implicit casts to/from bool
public static implicit operator bool(YesNo yn) {
return yn.Value;
}
public static implicit operator YesNo(bool b) {
return new YesNo() {Value = b};
}
// implement IXmlSerializable
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader) {
Value = (reader.ReadElementContentAsString() == "yes");
}
public void WriteXml(XmlWriter writer) {
writer.WriteString((Value) ? "yes" : "no");
}
}
次に、Fooクラスを次のように変更します。
[XmlRoot()]
public class Foo {
public YesNo Bar { get; set; }
}
YesNo
は暗黙的に bool
にキャスト可能である(およびその逆)ため、これを行うことができることに注意してください:
Foo foo = new Foo() { Bar = true; };
if ( foo.Bar ) {
// ... etc
つまり、boolのように扱うことができます。
そしてw00t!これにシリアル化します:
<Foo><Bar>yes</Bar></Foo>
また、正しくデシリアライズします。
XmlSerializerで遭遇した bool
を YesNo
に自動的にキャストする方法はおそらくありますが、まだ見つかりません。誰ですか?
他のヒント
非常にシンプル。代理プロパティを使用します。 XmlIgnoreを実際のプロパティに適用します。サロゲートは文字列であり、要素名のオーバーライドを受け取るXmlElement属性を使用する必要があります。オーバーライドで実際のプロパティの名前を指定します。代理プロパティは、実際のプロパティの値に基づいて異なる方法でシリアル化されます。また、サロゲートにセッターを提供する必要があります。セッターは、シリアル化された値に関係なく、実際のプロパティを適切に設定する必要があります。言い換えれば、両方の方向に進む必要があります。
Snip:
public class SomeType
{
[XmlElement]
public int IntValue;
[XmlIgnore]
public bool Value;
[XmlElement("Value")]
public string Value_Surrogate {
get { return (Value)? "Yes, definitely!":"Absolutely NOT!"; }
set { Value= (value=="Yes, definitely!"); }
}
}
ブール値を「yes」としてシリアル化する;または「いいえ」データ型をブール値から変更します。代わりに、ブール値を評価して&quot; yes&quot;を返す別のプロパティを追加できますか?または「いいえ」データ型に適切ですか? 「はい」を強制することもできます。または「いいえ」戻り値の型をそれらの値のみを指定する列挙型にすることにより。
public YesOrNo DoYouLoveIt
{
get { return boolToEvaluate ? YesOrNo.Yes : YesOrNo.No; }
}
それはやり過ぎかもしれませんが、あなたのニーズに答えるかもしれません。このような単純な値の列挙型を作成する唯一の理由は、値を制限することと、文字列を許可することです。
プロパティメソッドを使用しますが、文字列がyesまたはnoに等しいかどうかを確認する代わりに、文字列が(大文字と小文字を区別しない)&quot; YT1&quot;で始まるかどうかを確認することを好みます。これにより、ファイルにtrue、True、t、T、y、Y、yes、Yes、1などを含めることができます。これらはすべてtrueと評価されます。 falseはfalse、False、f、F、n、N、no、No、0などと指定できますが、trueと一致しないものはすべてfalseと評価されます。
あなたのプロパティの例は、おそらく最も簡単な方法でしょう。それが役立つ場合、属性はあなたの背中の後ろのクラスでISerializableを実装するので、それをパブリックプロパティにする必要はないと思います。逆シリアル化を有効にするには、単に set {Bar = value ==&quot; yes&quot ;; }
@Blorgbeard: オブジェクトクラスにこれらのYesNoクラスの1つ以上がある場合、 必ず要素全体を読んでください。
public void ReadXml(XmlReader reader)
{
string element = reader.ReadOuterXml();
int startIndex = element.IndexOf('>') + 1;
int length = element.LastIndexOf('<') - startIndex;
string text = (element.Substring(startIndex, length).ToLowerInvariant();
Value = (text == "yes");
}
そうしないと、問題が発生する可能性があります。
ReadXmlメソッドは、WriteXmlメソッドによって書き込まれた情報を使用してオブジェクトを再構成する必要があります。
このメソッドが呼び出されると、リーダーは、タイプの情報をラップする要素の先頭に配置されます。つまり、ただ シリアル化の開始を示す開始タグの前 オブジェクト。このメソッドが戻るとき、要素全体を読み取らなければなりません すべての内容を含む最初から最後まで。とは異なり WriteXmlメソッド、フレームワークはラッパー要素を処理しません 自動的に。あなたの実装はそうしなければなりません。観察しない これらの配置ルールにより、コードが予期しないランタイムを生成する可能性があります 例外または破損したデータ。
必要なことは、ディスプレイの問題のように聞こえます。アプリケーションで許可されている場合は、データ型をブール値のままにして、ユーザーインターフェイスに[はい/いいえ]を表示することをお勧めします。