近況、技術整理を兼ねて。

Static Dumpの容量がでかすぎてどうしようもないです。
あまりにもでかすぎるせいでYAML.netがタイムアウトするとか、オブジェクトにコンバートしようとしたら上手くいかないわでちょっと凹み状態です。

そこでYAMLを別の方法で変換するための方法を模索中デス。。。
どうもRubyが標準でライブラリを持っているとかなんとかなのでエクリプスに導入してそっち方面で勉強中ですが……

<EVE>CCP提供データについて

EVE ONLINEで活用するアプリケーションを作成したいけどデータが無い……と思っていましたが、
CCPの提供している関係データがResources - EVE: Developersで提供されていました。
あとはXML APIやCRESTの使用方法についてもHome — EVE Online Third-Party Developer Documentationで提供されていまして、リファレンスとして使用したいのですが……英語じゃないですかー!

さて、簡単な交易支援を行うために何が必要かを振り返ってみました。
一時期はコープのIT屋が提供していたツール(英名→IDコンバーター)を使用してEVE-Central: The EVE-Online Market Aggregator and Toolkitから値段を取り出したものをGoogleスプレッドシートに記入し、仕入れ先を求めて奔走していました。
で、何が必要かを考えるとシートに入力するための手間が一番面倒→省略したいもの→必要なものと考えたわけです。

私にとって面倒だったのは
・各種IDを調べること
これに尽きます。
この問題を解決するためには上記で提示した静的データをデシリアライズし、コンバーターを作る必要があるので何とかしたいところです。

<C#>WebRequestとWebResponseを使ってみよう。

前回はXDocumentしか使用できないぞ!と嘆いておりました……
が、勉強の結果により、WebRequestとWebResponseを使用できるようになったのでサンプルコードを投下します。
一部行数短縮のため改変した部分もあるため、サンプルの後ろに解説を挟みます。

//今回使用する名前空間たち
using System.Text;
using System.Net;
using System.IO;

namespace ExperimentWebRequest
{
    class Program
    {
        static void Main(string[] args)
        {
            //今回開くURL
            string str_URL = "https://api.eveonline.com/api/calllist.xml.aspx";

            //今回の主役であるリクエストさんとレスポンスさん。
            WebRequest Req = WebRequest.Create(str_URL);
            //Req.Method = "GET";   参考にしたコードではGETを設定していましたが、WebRequest.Methodの規定値は"GET"なので省略
            WebResponse Res = Req.GetResponse();
            
            //レスポンスに基づいたストリームをリーダーに投げ、読み込んでいます。
            StreamReader st_Reader = new StreamReader(Res.GetResponseStream(),new UTF8Encoding(false));
            string ReadedXML = st_Reader.ReadToEnd();
            
        }
    }
}
StreamReaderの引数について

今回使用しているパターンでの引数は(Stream型,Encoding型)です。
他所のコードでは、下のように記述していることもあります。
なお、私は1回しか使用しないなら変数化する必要は無い。というスタンスであるため、サンプルのように記述しています。

Stream st = Res.GetResponseStream();
Encoding enc = new UTF8Encoding(false);
StreamReader st_Reader = new StreamReader(st,enc);

なお、Encoding型についてはUTF-8なら上のように記述しますがシフトJISであるなら下記のように記述します。

Encoding.GetEncoing("shift_jis")


今回やってて気づいたのはライブラリ的なやつを使う場合はローカルが役に立たない(´・ω・`)
メソッドとかどうするんだこれー!状態であちこちから引きまくりですはい

<C#>XDocumentに触ってみる

さて、今回はLINQ to XMLに入ります。
というのも外部URLからデータを取得しようとすると手段が悉く潰れてしまい、XDocumentだけが生き残ったためです。
これに関してはリクエストを取得するとかで私の技術向上によっては対応するかもしれません

今回は「さわり」ということで先日に作成したXMLを読み込み、値をコンソール上に表示させるメソッドを作成しました。

サンプルXML

<?xml version="1.0" encoding="utf-8"?>
<nanashi-san xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <nanashi-sans>
    <nanashi-san id="0">
      <name>名無しさん</name>
      <hororific>さん</hororific>
    </nanashi-san>
    <nanashi-san id="1">
      <name>名無しくん</name>
      <hororific>くん</hororific>
    </nanashi-san>
    <nanashi-san id="2">
      <name>名無しさま</name>
      <hororific>さま</hororific>
    </nanashi-san>
    <nanashi-san id="3">
      <name>No Name</name>
      <hororific>英語なんでわかりません!</hororific>
    </nanashi-san>
    <nanashi-san id="4">
      <name>Anonymous</name>
      <hororific>英語なんでわかりません!</hororific>
    </nanashi-san>
  </nanashi-sans>
</nanashi-san>

サンプルコード

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//追加分
using System.IO;
using System.Xml.Linq;

namespace Experiment_XDocument
{
    class Program
    {
        static void Main(string[] args)
        {
            FileStream ReadFile = File.OpenRead("sample5.xml");
            XDocument Readed = XDocument.Load(ReadFile);

            var linqSample = Readed.Descendants("name");
            foreach(XElement ele in linqSample) { Console.WriteLine(ele.Value); }
            
        }
    }
}

出力結果

名無しさん
名無しくん
名無しさま
No Name
Anonymous



あまりにも手探りすぎてざっくりした内容になってしまいました。。解説すらやりづらい……
そもそも要素の名前が被りすぎて適正な検索すらかけれないっていう状態になったのでより良いXMLを掘ってきます。

<C#>XMLに属性を付与しよう。

まず目指しているものについて提示するのを忘れていました。
APIv2 Page Index - EVEDev

XMLの(デ)シリアライズについてはこれらのデータを取得できることを目標にしています。
で、これらを読み取るためには属性を定義してやらないと、読み込めないし書き込む際も苦労します。

なお先日投稿したエントリでシリアライズしたXMLについては下の通りです。

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfXmlTestObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <XmlTestObject>
    <Number>0</Number>
    <Name>名無しさん</Name>
  </XmlTestObject>
  <XmlTestObject>
    <Number>1</Number>
    <Name>Anonymous</Name>
  </XmlTestObject>
  <XmlTestObject>
    <Number>2</Number>
    <Name>NameLess</Name>
  </XmlTestObject>
</ArrayOfXmlTestObject>

これだけでは少し味気ないので、属性を駆使してもっとそれっぽくしてみましょう。
コードについては以下の通りです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using System.IO;


namespace XML_experiment
{
    class Program
    {
        //実行
        static void Main(string[] args)
        {
            string FileName = Console.ReadLine();
            if (!FileName.EndsWith(".xml")) { FileName += ".xml"; }
            
            Serialize(FileName);
            DeSerialize(FileName);
        }

        //シリアライズ
        static void Serialize(string fname)
        {

            var sample = new XmlTestObject();

            sample.ListIn(new NanashiSan(0, "名無しさん", "さん"));
            sample.ListIn(new NanashiSan(1, "名無しくん", "くん"));
            sample.ListIn(new NanashiSan(2, "名無しさま","さま"));
            sample.ListIn(new NanashiSan(3, "No Name","英語なんでわかりません!"));
            sample.ListIn(new NanashiSan(4, "Anonymous","英語なんでわかりません!"));

            var Serializer = new XmlSerializer(typeof(XmlTestObject));

            var Writer = new StreamWriter(fname, false, new UTF8Encoding(false));

            Serializer.Serialize(Writer, sample);
            Writer.Close();
        }

        //デシリアライズ
        static void DeSerialize(string fname)
        {

            var DeSerializer = new XmlSerializer(typeof(XmlTestObject));

            var Reader = new StreamReader(fname, new UTF8Encoding(false));

            var DeSerializedObject = (XmlTestObject)DeSerializer.Deserialize(Reader);

            Reader.Close();
        }
    }

    //格納用オブジェクト
    [XmlRoot("nanashi-list")] public class XmlTestObject
    {
        [XmlArray("nanashi-sans")]
        [XmlArrayItem("nanashi-san")]
        public List<NanashiSan> Nanashi { get; set; }

        public XmlTestObject() { Nanashi = new List<NanashiSan>(); }
        public void ListIn(NanashiSan nanashi) { this.Nanashi.Add(nanashi); }
    }

    public class NanashiSan
    {
        [XmlAttribute("id")]public int Number { get; set; }
        [XmlElement("name")]public string Name { get; set; }
        [XmlElement("hororific")]public string Honofiric { get; set; }

        //引数ありのコンストラクタを作成すると引数なしのコンストラクタを置いておかないとシリアライズできません。
        public NanashiSan() { }

        public NanashiSan(int num, string name,string hono)
        {
            this.Number = num;
            this.Name = name;
            this.Honofiric = hono;
        }
    }
}

で、これを実行したときのXMLファイルは以下のようになります。(ファイル名任意)

<?xml version="1.0" encoding="utf-8"?>
<nanashi-list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <nanashi-sans>
    <nanashi-san id="0">
      <name>名無しさん</name>
      <hororific>さん</hororific>
    </nanashi-san>
    <nanashi-san id="1">
      <name>名無しくん</name>
      <hororific>くん</hororific>
    </nanashi-san>
    <nanashi-san id="2">
      <name>名無しさま</name>
      <hororific>さま</hororific>
    </nanashi-san>
    <nanashi-san id="3">
      <name>No Name</name>
      <hororific>英語なんでわかりません!</hororific>
    </nanashi-san>
    <nanashi-san id="4">
      <name>Anonymous</name>
      <hororific>英語なんでわかりません!</hororific>
    </nanashi-san>
  </nanashi-sans>
</nanashi-list>

解説

属性について

C#コード中に記入した属性は今回5種類使用しています。
なお属性についてはXml.Serializationに格納されているため新たにusingする必要はありません。

XmlRoot

文字通り、当該XMLのroot(親)です。多分1つしか付加できないと思います。
上記サンプルではnanashi-listが該当します。

XmlElement

XMLを構成する要素です。
上記サンプルではnameやhonorificが該当します。

XmlAttribute

XMLの要素を装飾する値です。
上記サンプルではidが該当します。

XmlArrayとXmlArrayItem

XMLにおいて繰り返し要素を持つものに対して付加します。
Arrayは親の名前を、ArrayItemは子の名前を持ちます。
上記サンプルではnanashi-sansがArray、nanashi-sanがArrayItemです。

<C#>XMLの読み込み/書き込み

早速で申し訳ないけど凄く・・・書きづらいデス・・・
コードから重要な部分だけ抜き出して書こうと思います。

書き忘れていましたが、開発環境はVS15・C#2015です。
今回のコーディングについてはオブジェクトの内容をXMLファイルに保存、復元する: .NET Tips: C#, VB.NETを参考にさせていただきました。

また、作成時に追加されるネームスペース以外ではXml.SerializationとIOを使用しています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using System.IO;


namespace XML_experiment
{
    class Program
    {
        //実行
        static void Main(string[] args)
        {
            //ファイル名については指定可能に。
            string FileName = Console.ReadLine();
            //拡張子がついてないなら付ける。
            if (!FileName.EndsWith(".xml")) { FileName += ".xml"; }
            
            Serialize(FileName);
            DeSerialize(FileName);
        }

        //シリアライズ
        static void Serialize(string fname)
        {
        
            var listsample = new List<XmlTestObject>()
            {
                new XmlTestObject(0,"名無しさん"),
                new XmlTestObject(1,"Anonymous"),
                new XmlTestObject(2,"NameLess")
            };

            var Serializer = new XmlSerializer(typeof(List<XmlTestObject>));
            var Writer = new StreamWriter(fname, false, new UTF8Encoding(false));
            Serializer.Serialize(Writer, listsample);

            Writer.Close();
        }

        //デシリアライズ
        static void DeSerialize(string fname)
        {

            var DeSerializer = new XmlSerializer(typeof(List<XmlTestObject>));
            var Reader = new StreamReader(fname, new UTF8Encoding(false));
            var DeSerializedObject = (List<XmlTestObject>)DeSerializer.Deserialize(Reader);

            Reader.Close();
        }
    }

    //格納用オブジェクト
    public class XmlTestObject
    {
        public int Number { get; set; }
        public string Name { get; set; }
        
        //引数ありのコンストラクタを作成すると引数なしのコンストラクタを置いておかないとシリアライズできません
        public XmlTestObject() { }

        public XmlTestObject(int num, string name)
        {
            Number = num;
            Name = name;
        }
    }

}

……書き込みと読み込み自体はこんな短くて済むんですね。
問題はクラス設計になるかもです。

はじめに

当ブログはホビープログラマKaruraがC#を使用し、EVE ONLINEのアプリケーション開発を目指していく過程で得られた技術を公開していくブログです。

現状で取得を目指している技術については以下の通りです。

XMLおよびJSONの(デ)シリアライズ及びそれに伴うクラス設計

・OAuth2.0