指定された形式でXMLを出力しようとした時に毎回検索してはあっちこっちから情報拾ってる気がするのでまとめていく。
ちまちま増やしていくつもりです。
・環境
・C#7.0~8.0
・.Net Framework 4.7
・.Net Core 3.1
Nullable<T>=null
の項目のタグを出力しない
こんな場合。
モデル
[XmlRoot]
public class Library
{
[XmlElement]
public User[] Users { get; set; }
}
public class User
{
[XmlElement]
public int? Age { get; set; }
[XmlElement]
public string Name { get; set; }
}
出力
<?xml version="1.0" encoding="utf-8"?>
<Library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Users>
<Age xsi:nil="true" /> <!--これを出力したくない-->
<Name>user1</Name>
</Users>
</Library>
bool型で制御したいプロパティ名+Specifiedのプロパティを定義することでタグの出力/非出力を制御できるのでそれを利用します。
コード
[XmlRoot]
public class Library
{
[XmlElement]
public User[] Users { get; set; }
}
public class User
{
[XmlElement]
public int? Age { get; set; }
// Age == null の場合falseが返ってタグが出力されなくなる
// 完全にシリアライズ制御用のプロパティなのでBrowsable=falseにしてインテリセンスで表示されないようにもしています
[XmlIgnore, Browsable(false)]
public bool AgeSpecified => Age.HasValue;
[XmlElement]
public string Name { get; set; }
}
出力
<?xml version="1.0" encoding="utf-8"?>
<Library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Users>
<Name>user1</Name>
</Users>
</Library>
構造体のシリアライズ
変換処理を書くだけといえばそれだけ
[XmlRoot]
public class Library
{
[XmlIgnore]
public Color SomeColor { get; set; }
[XmlElement("FontColor"), Browsable(false)]
public string SomeColorValue
{
get { return $"#{SomeColor.A}{SomeColor.R}{SomeColor.G}{SomeColor.B}"; }
set { SomeColor = ColorTranslator.FromHtml(value); }
}
}
出力
<?xml version="1.0" encoding="utf-8"?>
<Library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FontColor>#12345678</FontColor>
</Library>
DateTimeのフォーマットなんかもこれでやらざるをえない気がする。
xmlnsを外す
ちょっと古いアプリとの連携とかで要求されがちな気がする。
xmlをプレーンテキストとして処理する場合とかにも
コード
class Program
{
static void Main(string[] args)
{
var app = new Library() { Names = new string[] { } }
using (var writer = new StreamWriter("application.xml"))
{
// 空白のnamespaceを用意する
var ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
var serializer = new XmlSerializer(typeof(Library));
serializer.Serialize(writer, app, ns); // 空白のnamespaceを使ってシリアライズ
}
}
}
[XmlRoot]
public class Library
{
public string[] Names { get; set; }
}
出力
<?xml version="1.0" encoding="utf-8"?>
<Library>
<Names />
</Library>
後書き
なんかもっといい方法あったら教えてほしいなって。