0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C#】XMLの要素名や値を動的に作成する方法をまとめてみた

Posted at

概要

C#でxmlテキストを作成する際に要素とコンテンツを動的に作成する方法を、自身の勉強を兼ねて記載してみました。

説明

xmlテキストにシリアライズするための階層構造になっているデータクラス群があるとします。
xmlの第2階層 (ルート要素の一つ下の子要素) 用のクラスは、紐づくクラスのプロパティの値から動的に要素と値を出力し、他のクラスは自身のプロパティをそのままシリアライズする形になります。
※第2階層のみ動的に要素名と値を出力するイメージです。

コード

前提として、シリアライズ後のxmlのイメージは以下になります。

<?xml version="1.0" encoding="utf-8"?>
<ROOT xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <HOGE>AAAA</HOGE>
  <FUGA>BBBB</FUGA>
  <PIYO>CCCC</PIYO>
  <CONTENT_LIST>
    <CONTENT>
      <TEXT>1</TEXT>
    </CONTENT>
    <CONTENT>
      <TEXT>2</TEXT>
    </CONTENT>
    <CONTENT>
      <TEXT>3</TEXT>
    </CONTENT>
  </CONTENT_LIST>
</ROOT>

第2階層の<HOGE><FUGA><PIYO>部分を動的に作成しているイメージです。

第2階層用のクラス

xml第2階層用のクラスです。
Layer2Itemsというプロパティに、xmlの第2階層の要素名と値のまとまりが入っています。

Layer2.cs
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

namespace Sample
{
    [XmlRoot("ROOT")]
    public class Layer2
    {
        [XmlAnyElement]
        public List<Layer2Item> Layer2Items { get; set; }

        [XmlElement("CONTENT_LIST")]
        public ContentList ContentList { get; set; }

        public void Set(List<Layer2Info> layer2Infos)
        {
            // 第2階層を作成する
            var layer2Items = new List<Layer2Item>();
            foreach (var layer2Info in layer2Infos.OrderBy(x => x.Index))
            {
                var item = new Layer2Item();
                item.Set(layer2Info);

                // プロパティに情報をセット
                layer2Items.Add(item);
            }

            Layer2Items = layer2Items;

            SetContentList(new ContentList());
        }

        private void SetContentList(ContentList contentList)
        {
            contentList.Set();
            this.ContentList = contentList;
        }

        public string CreateXmlText()
        {
            // シリアライズ
            string xmlText = Serialize();

            // &のエスケープコードを消去し返却
            return xmlText.Replace("amp;", "");
        }

        private string Serialize()
        {
            var serializer = new XmlSerializer(GetType());
            var writer = new StringWriterUTF8();

            serializer.Serialize(writer, this);

            return writer.ToString();
        }

        private class StringWriterUTF8 : StringWriter
        {
            public override Encoding Encoding
            {
                get
                {
                    return Encoding.UTF8;
                }
            }
        }
    }
}

説明

XmlAnyElement属性

予め定義していないXML要素を動的に処理するために使用するC#の属性です。
ここではxmlの第2階層の要素名や値を保持しているLayer2Itemsプロパティに属性を付与しています。

Layer2クラスのプロパティに出力する情報クラス

Layer2クラスのLayer2Itemsプロパティの型となっているクラスです。
このクラス一つ分がxmlの第2階層の要素一つ分です。
Nameプロパティが要素名、Valueプロパティが要素の値です。

Layer2Item.cs
using System;
using System.Linq;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace Sample
{
    public class Layer2Item : IXmlSerializable
    {
        /// <summary>
        /// 要素名
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 値
        /// </summary>
        public string Value { get; set; }

        /// <summary>
        ///  1要素分のデータを取得する
        /// </summary>
        /// <returns>1要素分のデータ</returns>
        public void Set(Layer2Info layer2Info)
        {
            Name = layer2Info.Name;
            Value = layer2Info.Value;
        }

        public XmlSchema GetSchema()
        {
            throw new NotImplementedException();
        }

        public void ReadXml(XmlReader reader)
        {
            throw new NotImplementedException();
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteElementString(Name, Value);
        }
    }
}

説明

IXmlSerializableインターフェース

オブジェクトをXMLに変換する方法を完全に制御できるようにするインターフェースです。
IXmlSerializableWriteXml()はオブジェクトの状態をxml形式で出力するためのメソッドです。このメソッドの中でXmlWriterクラスのWriteElementString()を使用し、要素名と値を指定してxml要素を生成します。

Layer2クラスのプロパティに出力する情報クラス一つ分

上記のLayer2Itemはこのデータクラスの値を使用しています。
このデータクラスには、ユーザー操作等でxml出力するための要素名や値があらかじめ格納されているイメージです。
Nameプロパティが要素名、Valueプロパティが要素の値です。
Indexプロパティを使用して連番とすることで、このデータクラス群 (Layer2Infos) のどの順番でxml出力するかも操作できます。

Layer2Info.cs
    public class Layer2Info
    {
        public int Index { get; set; }

        public string Name { get; set; }

        public string Value { get; set; }
    }

CONTENT_LIST用のクラス

xmlのCONTENT_LISTに紐づくクラスです。
contentsプロパティにCONTENT用のクラス群を保持しています。

ContentList.cs
using System.Collections.Generic;
using System.Xml.Serialization;

namespace Sample
{
    public class ContentList
    {
        [XmlElement("CONTENT")]
        public List<Content> contents { get; set; }

        public void Set()
        {
            var contents = new List<Content>();

            // ここではnewしているが、ここは本来はxml出力する何かしらの値を取得する
            var texts = new List<string>();

            foreach (string text in texts)
            {
                var content = new Content();
                content.Set(text);

                contents.Add(content);
            }

            this.contents = contents;
        }
    }
}

CONTENT用のクラス

xmlのCONTENTに紐づくクラスです。
TextプロパティがCONTENTの子要素として出力する値です。

Content.cs
using System.Xml.Serialization;

namespace Sample
{
    public class Content
    {
        [XmlElement("TEXT")]
        public string Text { get; set; }

        public void Set(string text)
        {
            Text = text;
        }
    }
}

xmlデータの出力

xmlデータの出力処理です。
先に出力するデータをセットしておき、その後にLayer2クラスのCreateXmlText()を呼出してシリアライズされたxmlのテキストを取得し、その後に任意の場所に出力しています。

        // 出力するデータをセット
        List<Layer2Info> layer2Infos = (2階層に出力するLayer2Infoクラスのリスト);
        var layer2 = new Layer2();
        layer2.Set(layer2Infos);

        // XMLテキストを作成
        string xmlText = layer2.CreateXmlText();

        // XMLを出力
        using (var sw = new StreamWriter("出力先パス", false, new System.Text.UTF8Encoding(false)))
        {
            sw.Write(xmlText);
        }

シリアライズ後のxmlデータ

最初にも記載しましたが、以下がシリアライズ後のxmlデータです。
<HOGE><FUGA><PIYO>要素の要素名と値が、それぞれLayer2ItemクラスのNameプロパティやValueプロパティに入っていた形です。
また、ContentListクラスとContentクラスはプロパティの値をそのまま出力できています。
動的に要素名を生成するLayer2クラスと、属性名と値を指定してそのままシリアライズしているContentListクラスとContentクラスのように、組み合わせることもできます。

<?xml version="1.0" encoding="utf-8"?>
<ROOT xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <HOGE>AAAA</HOGE>
  <FUGA>BBBB</FUGA>
  <PIYO>CCCC</PIYO>
  <CONTENT_LIST>
    <CONTENT>
      <TEXT>1</TEXT>
    </CONTENT>
    <CONTENT>
      <TEXT>2</TEXT>
    </CONTENT>
    <CONTENT>
      <TEXT>3</TEXT>
    </CONTENT>
  </CONTENT_LIST>
</ROOT>

終わりに

XmlAnyElement属性やIXmlSerializableインターフェースを使用すると、柔軟にxmlを作成できることがわかりました。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?