余小章 @ 大內聖殿
祕訣無它, 唯勤而已, by 余小章

导航

 

ezTRACK 是一家全球性的RFID、條碼追蹤電子交換平台,然而EPCIS即是電子產品程式碼資訊服務(Electronic Product Code Information Services),為EPC資料提供了一整套標準介面,今天重點不是它們兩個,而是ezTRACK所給我的文件,我要批次產生文件然後上傳到它們的Server,以下就是ezTrack的Xml文件範本:

<?xml version="1.0" encoding="utf-8"?>
<epcis:EPCISDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sensor="http://epcis.gs1hk.org/ns/sensor" xmlns:gs1hk="urn:epcglobal:gs1hk:xsd:ext" schemaVersion="1" creationDate="2010-09-15T04:07:52" xmlns:epcis="urn:epcglobal:epcis:xsd:1">
  <EPCISBody>
    <EventList>
      <ObjectEvent>
        <eventTime>2011-12-25T17:04:52</eventTime>
        <eventTimeZoneOffset>+08:00</eventTimeZoneOffset>
        <epcList>
          <epc>BBAA99887766554400085172</epc>
          <epc>BBAA99887766554400085173</epc>
        </epcList>
        <action>OBSERVE</action>
        <bizStep>urn:epcglobal:fmcg:bizstep:Gate_In</bizStep>
        <bizLocation>
          <id>urn:epcglobal:fmcg:loc.MMMMM.202.MZMFG_Warehouse_Gate_Door,414.Gate_Door2</id>
        </bizLocation>
        <bizTransactionList>
          <bizTransaction type="urn:gs1hk:ext:order">China</bizTransaction>
        </bizTransactionList>
        <sensor:temperature>20.5</sensor:temperature>
        <sensor:state>Alram</sensor:state>
        <sensor:temperaturereporturl>http://www.gts-portal.co/Z/Page/TempChart.aspx?EPC=BBAA99887766554400085172&amp;Date=2011-12-25T17:04:52</sensor:temperaturereporturl>
      </ObjectEvent>
    </EventList>
  </EPCISBody>
</epcis:EPCISDocument>
 

一看到這個文件時,我就想要利用XSD.exe來處理(請參考[XML] XSD Convert XML),於是就去找它的schema快速處理http://www.epcglobalinc.org/standards/epcis/epcis_1_0-schema-20070412.zip,但一直沒有辦法成功,兩岸三地的高手都說xsd檔有問題

http://social.msdn.microsoft.com/Forums/zh-TW/239/thread/8e62987a-1e67-4feb-8856-ee801ee2baa2

http://social.msdn.microsoft.com/Forums/zh-TW/xmlwebserviceszhchs/thread/df0a2242-99bc-4097-9d79-1a28ed089f53

於是乎動手自己寫Entity Class來序列化為Xml念動便油然而生,這得定義Xml Attribute,我們先拆成小塊處理,雖然實作過程有碰到些問題,但總算解決了。


首先是bizLocation區塊的定義,我猜想id結構應該會是集合,所以用List<string>

image

 

/// <summary>
/// 位置
/// </summary>
[Serializable, XmlRoot("bizLocation")]
public class BizLocation
{
    /// <summary>
    /// 位置ID
    /// </summary>
    private List<string> _Ids= new List<string>();
    [XmlElement("id")]
    public List<string> Ids
    {
        get { return _Ids; }
        set { _Ids = value; }
    }
}

epcList我則是指定XmlArrayItem屬性,這跟上述bizLocation屬性最後產生的結果會一樣

image 

 

private List<string> _epcList = new List<string>();
/// <summary>
/// EPC 編號清單
/// EPC List
/// </summary>
[XmlArrayItem("epc")]
public List<string> epcList
{
    get { return this._epcList; }
    set { this._epcList = value; }
}


bizTransaction裡有XmlAttribute type,所以要特別處理下,Content則是用來裝BizTransaction用

image

/// <summary>
/// 交易內容
/// </summary>
[Serializable, XmlRoot("bizTransaction")]
//[Serializable]
public class BizTransaction
{
    private string _type = "urn:gs1hk:ext:order";
    /// <summary>
    /// 交易內容屬性
    /// </summary>
    [XmlAttribute("type")]
    public string type
    {
        get { return this._type; }
        set { this._type = value; }
    }
    /// <summary>
    /// 內容
    /// </summary>
    [XmlText()]
    public string Content { get; set; }
}

sensor 指的是xml的命名空間,所以需要為這些屬性定義Namespace

image 

 

/// <summary>
/// Tag 溫度
/// </summary>
[XmlElement("temperature", Namespace = "http://epcis.gs1hk.org/ns/sensor")]
public string Temperature { get; set; }

/// <summary>
/// Tag 的狀態
/// </summary>
[XmlElement("state", Namespace = "http://epcis.gs1hk.org/ns/sensor")]
public string State { get; set; }

/// <summary>
/// temperaturereporturl 超連結
/// </summary>
[XmlElement("temperaturereporturl", Namespace = "http://epcis.gs1hk.org/ns/sensor")]
public string TemperaturerEportUrl { get; set; }


整個ObjectEvent結構在類別裡的定義如下:

image

 

/// <summary>
/// 事件類型
/// </summary>
/// <seealso cref="ObjectEvent"/>
[Serializable, XmlRoot("ObjectEvent")]
public class ObjectEvent
{
    #region 固定欄位

    #region EventTime
    /// <summary>
    /// Tag 當時的時間
    /// Event Time
    /// </summary>
    [XmlElement("eventTime")]
    public string EventTime { get; set; }
    #endregion

    #region EventTimeZoneOffset
    /// <summary>
    /// Time Zone offset
    /// 時差
    /// </summary>
    [XmlElement("eventTimeZoneOffset")]
    public string EventTimeZoneOffset { get; set; }

    #endregion

    #region epcList
    private List<string> _epcList = new List<string>();
    /// <summary>
    /// EPC 編號清單
    /// EPC List
    /// </summary>
    [XmlArrayItem("epc")]
    public List<string> epcList
    {
        get { return this._epcList; }
        set { this._epcList = value; }
    }
    #endregion

    #region action
    /// <summary>
    /// 事件動作
    /// Action
    /// </summary>
    [XmlElement("action")]
    public string EventAction { get; set; }
    #endregion

    #region bizStep
    /// <summary>
    /// 商業流程
    /// BizStep
    /// </summary>
    [XmlElement("bizStep")]
    public string BizStep { get; set; }
    #endregion

    #region disposition
    /// <summary>
    /// 目前配置
    /// Disposition
    /// </summary>
    [XmlElement("disposition")]
    public string Disposition { get; set; }
    #endregion

    #region bizLocation
    private BizLocation _BizLocation = new BizLocation();
    /// <summary>
    /// 位置
    /// bizLocation
    /// </summary
    [XmlElement("bizLocation")]
    public BizLocation BizLocation
    {
        get { return this._BizLocation; }
        set { this._BizLocation = value; }
    }

    #endregion

    #region bizTransaction

    private BizTransactionList _BizTransactionList = new BizTransactionList();
    /// <summary>
    /// 交易清單
    /// </summary>
    [XmlElement("bizTransactionList")]
    public BizTransactionList BizTransactionList
    {
        get { return this._BizTransactionList; }
        set { this._BizTransactionList = value; }
    }
    #endregion

    #endregion

    #region 可擴充欄位
    /// <summary>
    /// Tag 溫度
    /// </summary>
    [XmlElement("temperature", Namespace = "http://epcis.gs1hk.org/ns/sensor")]
    public string Temperature { get; set; }

    /// <summary>
    /// Tag 的狀態
    /// </summary>
    [XmlElement("state", Namespace = "http://epcis.gs1hk.org/ns/sensor")]
    public string State { get; set; }

    /// <summary>
    /// temperaturereporturl 超連結
    /// </summary>
    [XmlElement("temperaturereporturl", Namespace = "http://epcis.gs1hk.org/ns/sensor")]
    public string TemperaturerEportUrl { get; set; }
    #endregion
}


接著是ObjectEvent上層EventList

image

/// <summary>
/// 事件清單
/// </summary>
[Serializable, XmlRoot("EventList")]
public class EventList
{
    private ObjectEvent _ObjectEvent = new ObjectEvent();
    /// <summary>
    /// 事件類型
    /// </summary>
    [XmlElement("ObjectEvent")]
    public ObjectEvent ObjectEvent
    {
        get { return this._ObjectEvent; }
        set { this._ObjectEvent = value; }
    }
}


還有EventList的上層EPCISBody

image

/// <summary>
/// EPCIS 內文
/// </summary>
[Serializable, XmlRoot("EPCISBody")]
public class Body
{
    EventList _EventList = new EventList();
    /// <summary>
    /// 事件清單
    /// </summary>
    [XmlElement("EventList")]
    public EventList EventList
    {
        get { return this._EventList; }
        set { this._EventList = value; }
    }
}


EPCISBody的上層EPCISDocument

image 

/// <summary>
/// EPCIS Root
/// </summary>
[Serializable, XmlRoot("EPCISDocument", Namespace = "urn:epcglobal:epcis:xsd:1")]
public class EPCISDocument
{
    private Body _EPCISBody = new Body();
    /// <summary>
    /// EPCIS 內容
    /// </summary>
    [XmlElement(ElementName = "EPCISBody", Namespace = "")]
    public Body EPCISBody
    {
        get { return this._EPCISBody; }
        set { this._EPCISBody = value; }
    }

    private decimal _SchemaVersion = (decimal)1.0;
    /// <summary>
    /// 結構版本
    /// </summary>
    [XmlAttribute("schemaVersion")]
    public decimal SchemaVersion
    {
        get { return this._SchemaVersion; }
        set { this._SchemaVersion = value; }
    }
    private string _CreationDate = "2010-09-15T04:07:52";
    /// <summary>
    /// 認証日期
    /// </summary>
    [XmlAttribute("creationDate")]
    public string CreationDate
    {
        get { return this._CreationDate; }
        set { this._CreationDate = value; }
    }
}

 

剛剛我們在一些屬性定義了Xml Namespace,如下圖:

image

還要設定XmlSerializerNamespaces 類別,等會序列化時會用的到

XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("epcis", "urn:epcglobal:epcis:xsd:1");
namespaces.Add("sensor", "http://epcis.gs1hk.org/ns/sensor");
namespaces.Add("gs1hk", "urn:epcglobal:gs1hk:xsd:ext");
namespaces.Add("xsi", http://www.w3.org/2001/XMLSchema-instance);



然後再為這些欄位定義一個Config類別,用它來對外公開主要設定結構欄位有哪些

/// <summary>
/// EPSIC設定檔
/// </summary>
[Serializable]
public class EPCISConfig
{
    #region FileName
    /// <summary>
    /// 完整檔案路徑
    /// </summary>
    public string FileName { get; set; }
    #endregion

    #region EventTime
    private DateTime? _EventTime = null;
    /// <summary>
    /// UTC時間
    /// </summary>
    public DateTime? EventTime
    {
        get
        {
            //if (this._EventTime == null)
            //    this._EventTime = DateTime.Now;

            return this._EventTime;
        }
        set { this._EventTime = value; }
    }
    #endregion

    #region EventTimeZoneOffset
    private string _EventTimeZoneOffset = null;
    /// <summary>
    /// 時差
    /// </summary>
    public string EventTimeZoneOffset
    {
        get
        {
            if (string.IsNullOrEmpty(this._EventTimeZoneOffset))
            {
                int day = TimeZoneInfo.Local.BaseUtcOffset.Days;

                int hours = TimeZoneInfo.Local.BaseUtcOffset.Hours;
                int minutes = TimeZoneInfo.Local.BaseUtcOffset.Minutes;
                string localZone = "";
                if (hours > 0)
                    localZone = string.Format("+{0}:{1}", hours.ToString().PadLeft(2, '0'), minutes.ToString().PadLeft(2, '0'));
                else if (hours < 0)
                    localZone = string.Format("-{0}:{1}", hours.ToString().PadLeft(2, '0'), minutes.ToString().PadLeft(2, '0'));
                this._EventTimeZoneOffset = localZone;
            }
            return this._EventTimeZoneOffset;
        }
        set { this._EventTimeZoneOffset = value; }
    }
    #endregion

    #region EpcList
    private List<string> _EpcList = new List<string>();
    /// <summary>
    /// EPC 清單
    /// </summary>
    public List<string> EpcList
    {
        get { return this._EpcList; }
        set { this._EpcList = value; }
    }
    #endregion

    #region Action
    private string _Action;
    /// <summary>
    /// 事件動作
    /// Action
    /// </summary>
    public string Action
    {
        get { return this._Action; }
        set { this._Action = value; }
    }
    #endregion

    #region BizStep
    /// <summary>
    /// 商業流程
    /// </summary>
    public string BizStep { get; set; }
    #endregion

    #region Disposition
    /// <summary>
    /// 目前配置
    /// </summary>
    public string Disposition { get; set; }
    #endregion

    #region BizTransactionList

    private List<string> _TransactionList = new List<string>();
    /// <summary>
    /// 交易清單
    /// </summary>
    public List<string> TransactionList
    {
        get { return this._TransactionList; }
        set { this._TransactionList = value; }
    }
    #endregion

    #region LocationList
    private List<string> _LocationList = new List<string>();
    /// <summary>
    /// 位置清單
    /// </summary>
    public List<string> LocationList
    {
        get { return _LocationList; }
        set { _LocationList = value; }
    }
    #endregion

    #region 擴充欄位
    #region CurrentTemperature
    /// <summary>
    /// 目前時間
    /// </summary>
    public string Temperature { get; set; }
    #endregion

    #region CurrentState
    /// <summary>
    /// 目前狀態
    /// </summary>
    public string State { get; set; }
    #endregion

    #region TemperatureURL
    /// <summary>
    /// 溫度查詢網址
    /// </summary>
    public string TemperatureURL { get; set; }
    #endregion

    #endregion
}


Document工廠類別則是用來實體化EPCISDocument 以及建立實體Xml檔案

public class Document
{
    public Document(EPCISConfig Config)
    {
        if (Config == null)
            throw new ArgumentNullException("Config");
        if (string.IsNullOrEmpty(Config.FileName))
            throw new ArgumentNullException("Config.FileName");

        XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
        namespaces.Add("epcis", "urn:epcglobal:epcis:xsd:1");
        namespaces.Add("sensor", "http://epcis.gs1hk.org/ns/sensor");
        namespaces.Add("gs1hk", "urn:epcglobal:gs1hk:xsd:ext");
        namespaces.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
        EPCISDocument doc = this.createEpcIsDocument(Config);
        this.ToXml(Config.FileName, doc, namespaces);
    }
    EPCISDocument createEpcIsDocument(EPCISConfig Config)
    {
        EPCISDocument epcisDocument = new EPCISDocument();
        string eventTime = string.Format("{0:s}", (DateTime)Config.EventTime);
        epcisDocument.EPCISBody.EventList.ObjectEvent.EventTime = eventTime;
        epcisDocument.EPCISBody.EventList.ObjectEvent.EventTimeZoneOffset = Config.EventTimeZoneOffset;
        epcisDocument.EPCISBody.EventList.ObjectEvent.epcList = Config.EpcList;
        epcisDocument.EPCISBody.EventList.ObjectEvent.EventAction = Config.Action;
        epcisDocument.EPCISBody.EventList.ObjectEvent.BizStep = Config.BizStep;
        epcisDocument.EPCISBody.EventList.ObjectEvent.Disposition = Config.Disposition;
        epcisDocument.EPCISBody.EventList.ObjectEvent.BizLocation.Ids = Config.LocationList;
        foreach (var item in Config.TransactionList)
        {
            epcisDocument.EPCISBody.EventList.ObjectEvent.BizTransactionList.BizTransaction.Add(new BizTransaction() { Content = item });
        }

        epcisDocument.EPCISBody.EventList.ObjectEvent.State = Config.State;
        epcisDocument.EPCISBody.EventList.ObjectEvent.Temperature = Config.Temperature;
        epcisDocument.EPCISBody.EventList.ObjectEvent.TemperaturerEportUrl = Config.TemperatureURL;
        return epcisDocument;
    }
    void ToXml(string FileName, object Object, XmlSerializerNamespaces Namespace)
    {
        XmlSerializer xml = null;
        Stream stream = null;
        StreamWriter writer = null;
        try
        {
            xml = new XmlSerializer(Object.GetType());
            stream = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.Read);
            writer = new StreamWriter(stream, Encoding.UTF8);
            xml.Serialize(writer, Object, Namespace);
        }
        catch
        {
            throw;
        }
        finally
        {
            if (writer != null)
                writer.Close();
            if (stream != null)
                stream.Close();
        }
    }
}


在客戶端,定義EPCISConfig ,並實體化Document 即可

private void button1_Click(object sender, EventArgs e)
{
    string file = Application.StartupPath + "\\" + "Test.xml";
    EPCISConfig config = new EPCISConfig();

    DateTime date = DateTime.Now.ToUniversalTime();
    string time = string.Format("{0:s}", (DateTime)date);
    string epc = "BBAA99887766554400085172";
    config.FileName = file;
    //實體化Config並帶入相關欄位
    config.BizStep = "urn:epcglobal:fmcg:bizstep:Gate_In";
    config.State = "Alram";
    config.Action = "OBSERVE";
    config.Temperature = "20.5";
    config.EventTime = date;
    config.LocationList.Add("urn:epcglobal:fmcg:loc.MMMMM.202.MZMFG_Warehouse_Gate_Door,414.Gate_Door2");
    string url = string.Format("http://www.gts-portal.co/Z/Page/TempChart.aspx?EPC={0}&Date={1}", epc, time);
    config.TemperatureURL = url;
    config.EpcList.Add(epc);
    config.EpcList.Add("BBAA99887766554400085173");

    config.TransactionList.Add("China");

    Document doc = new Document(config);

}

在實作這個Xml時我有碰到一些問題,這些問題我在半年多前就已經透過MSDN論壇解決,感謝兩岸三地的高手協助,今日特與分享實作結果

http://social.msdn.microsoft.com/Forums/zh-TW/239/thread/2c8d5930-e5ea-4f6a-8987-f19bd589af22

http://social.msdn.microsoft.com/Forums/zh-TW/xmlwebserviceszhchs/thread/4809cf9e-fb53-42f7-98c5-8b77ca0b2d92

範例下載:

System.ezTrack.Xml.zip


posted on 2011-12-27 15:09  余小章  阅读(271)  评论(0编辑  收藏  举报