日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

用C#+XMI技术进行UML模型捕获

發布時間:2024/4/17 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用C#+XMI技术进行UML模型捕获 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

有許多不同的方法可用于捕獲XML模型數據并且把它放到一個數據存儲中,正如你所期望的,包括使用XSLT技術。但是我想使用一種不同的方法-使用C#語言。XSLT是一個用于改變XML文件的好選擇,但是對于更廣闊的不僅僅是轉變數據的應用軟件來說,C#或者另外的象Java這樣的高級語言提供了更大的靈活性。

  在本文中,我將展示如何通過使用XMI和C#來剖析一個UML發布圖。首先,我展示一個該方法的簡單的發布圖,所在環境為一個虛構的汽車出租公司并使用 C#來捕獲一些數據。這種數據可以被容易地加到一個數據庫(它已經是ADO調用的相當容易的一部分)上去或者作為更大些的一個基于資產的管理系統的一部分。在每一個示例中,我將逐漸增加原始圖和能夠獲取的信息的復雜性。

  一、 示例1-查找方法的名字

  我要做的第一件事情是捕獲來自于汽車出租公司的所有方法的名字。共有五個方法,它們是以UML發布圖形描述的(見圖1)。在上一篇文章中,我展示了如何用一個XML文檔來描述一個發布圖。為此,首先要創建該圖,然后把它輸出到一個XMI文件(企業架構)或解壓(MagicDraw)。(在這篇文章中,我再次使用了SparxSystems.com提供的企業架構。)

圖1.五個方法:圖中結點描述了汽車出租公司的方法。每一個結點為一個方法名字。
  我將首先開發一簡單main程序-它提示用戶輸入描述一個有效的XMI文檔的XML文檔的名字。一旦輸入文件名字,它就被傳遞到一個分析XMI文檔的對象并打印輸出方法名字。
using System;
using System.Text;
namespace XMI_1{
public class ConsoleUtils{
 public static string ReadString(string msg) {
  Console.Write(msg); return System.Console.ReadLine();
 }
 public static void WriteString(string msg)
 { System.Console.WriteLine(msg); }
 public static void Main(string[] args) {
  string name = ReadString("Please enter the XMI filename : ");
  NodeParse np = new NodeParse(name);
  System.Console.ReadLine();
 }
}
}
   下一步是分析XMI文檔。為此,我必須創建一個XMLTextReader的實例并循環操作直到沒有結點為止。XMLNodeType.Element 檢查每一個XML元素并且在元素是一個結點的情況下把它打印輸出到控制臺。該元素名字資格為"UML:Node",然而通過使用 _readXMI.LocalName只有元素名字的"Node"被讀取。詳細代碼參見列表1。

  二、 示例2-增加模板

  第二個示例重構了第一個示例來捕獲方法的名字和"pc server"模板-這是一個用來決定每個結點是一個方法的UML方法。圖3顯示增加了模板后的方法的發布圖。

  第一步是修改前面的代碼以識別新的模板來操縱AddNode()方法。

圖3.增加了模板之后:每個模板描述了結點的類型-不管它是一個PC服務器,PC客戶端或者是另外一些描述該結點的目標。
private void AddNode(XmlTextReader p_readXMI)
{
 string nodeID;
 string nodeName;
 string stereotypeName;
 nodeID = p_readXMI.GetAttribute("name");
 nodeName = p_readXMI.GetAttribute("xmi.id");
 Console.Write(nodeID);
 Console.Write(" -> ");
 Console.WriteLine(nodeName);
 while (p_readXMI.Read() && (p_readXMI.NodeType == XmlNodeType.Element ||?
p_readXMI.NodeType== XmlNodeType.Whitespace))
 {
  switch (p_readXMI.LocalName)
  {
   case "ModelElement.stereotype":
    while (p_readXMI.Read() && (p_readXMI.NodeType == XmlNodeType.Element ||?
p_readXMI.NodeType == XmlNodeType.Whitespace))
    {
     if (p_readXMI.LocalName == "Stereotype")
     {
      stereotypeName = p_readXMI.GetAttribute("name");
      Console.WriteLine("Stereotype = " + stereotypeName);
     }
    }
   break;
  }
 }
}
   特別要注意的是一個idiom(對某個語言特有的一個低級別的模式)-我用來查找在另外一些元素內部的XML元素。我在p_readXMI.Read循 環中增加了代碼來檢查元素或者空格(在XML文檔中,這是些空格字符)。只有每個元素結點在XML文檔中適當的層次上處理時,這個idiom才工作。

  用這種方式對元素進行封裝,結果不很理想。例如,在下面的UML中使用idiom代碼將產生所不希望的結果:
?

<UML:Node name="Leasing">
<UML:TagName name="Test">
</UML:Node name="SmallLeasing">
</UML:TagName>
</UML:Node>

?


圖4.示例2的輸出結果:在示例1中的結點名字/id之后,列出每個模板。


   第一個元素被作為一個結點處理,第二個元素被忽略并在初始循環中退出,而第三個元素被作為在同一級上的第一個正常結點處理。為了修正這個問題,你可以使 用XMLNodetype.Endelement來檢查元素的結束標簽。在本文中,這不是個問題而保存額外的代碼要求檢查結尾元素。
XMI中的模板被封裝在結點元素中。該示例中的代碼檢查名字為"ModelElement.Stereotype"的元素并且使用剛才討論的相同的idiom來處理一個"模板"類型的封裝元素,然后把它打印輸出到屏幕上(見圖4)。(列表3列出了示例2的完全的源碼。)
  三、 示例3-添加硬件信息

  從資產管理的角度來看,捕獲方法的名字和它們的模板并沒有多大用處。當然,另一方面,如果你的圖包含了描述正在使用的硬件信息也可能是非常有用的:例如,基于UML發布圖把你所有的硬件保存到一個數據庫將能夠使你跟蹤方法、客戶及其如何進行彼此聯系的。

   在UML中,硬件結點都貼有用來識別它們屬性的"標簽"。每一個標簽都是在建模工具(這里是企業架構)中產生而且由建模器所定義(或者有時保存成一個 UML剖面文件)。在本示例中,我為CPU、磁盤大小、內存大小、目的、注意事項以及賣主等創建了標簽(見圖5)。每個標簽具有一個值-或者被賦予一個基 本類型(字符串,整型……)或者從一個可用值列表中選擇其一。無論如何,保持與所用值的一致性是很重要的。如果你把"GHT"用于CPU以描述 "gigahertz hyper-threaded",那么對每個CPU標簽,你都要使用相同的約定。
?


圖5.示例2的增加硬件到方法/模板圖,我添加了描述每個結點的硬件的標簽。我把一個客戶添加到示例"Mary Machine"來說明還有一個"pc client"模板。


   新的重構的代碼與以前的一樣,但是增加了讀取標簽的代碼。在此,XMI并沒有如你所盼的那樣封裝結點內的標簽。作為代替,每個屬性是一個 "TaggedValue"元素-它通過使用"modelElement"屬性來參考引用屬性的結點標識符(XML.id)。這樣做的困難在于結點元素必 須在標簽元素之前被讀取,并且每個結點元素必須被保存-為使標簽元素依附于其上。

  在XML中,存在兩種讀取文檔的方法。第一種是讀取 完整的文檔并把它以一棵樹保存到內存中-這里每個元素是從根元素開始構建的層次結構的一部分。這就是DOM模型,是較佳的適用于小型文檔的方法。第二種方 法是,讀取文檔時,每次分析一個元素。SAX就是這種方法的一個示例并且它被當作推模型,因為由它分析文檔并返回分析后的文檔(推它)而不需要提示。

   另外一種方法是微軟的XMLReaders(XMLTextReader派生于它)-它是一個拉模型,因為當下一個元素被分析時,控制掌握在程序中。我 在此使用的XML文檔很小,但是我分析過的一些文件是超過了500,000行的文本文件,這導致我求助于XMLReader方法。這種方法的一個不足是要 求結點應出現在標簽元素之前。

  為了保存結點我需要使用一個鍵/值容器。最易于使用的是Hashtable。在重構主程序中(見下),我使用了Hashtable中的枚舉能力以及用IDictionary枚舉器來打印方法結點。
?

public static void Main(string[] args){
 Hashtable mainHash;
 IDictionaryEnumerator ienum;
 Node tNode;
 string name = ReadString("Please enter the XMI filename : ");
 NodeParse np = new NodeParse(name);
 mainHash = np.getNodes();
 ienum = mainHash.GetEnumerator();
 while (ienum.MoveNext()) {
  tNode = (Node)ienum.Value;
  System.Console.WriteLine("Node ="+tNode.name+" CPU= "+tNode.CPU);
 }
 System.Console.ReadLine();
}


  我重構了nodeParse對象以用于檢查元素"TaggedValue"并且調用AddAttributeNode-它負責在哈希表中查找正確的結點并且通過一個case語句把標簽添加到該結點上。相應的類NodeParse顯示于列表4中。

  這個結點類僅僅是一個存儲狀態的對象。每一個標簽都有它自己的屬性。注意,這個結點類的構造器要求該對象必須用服務器名字初始化。?
?

using System;
using System.Text;
namespace XMI_1
{
 class Node{
  string _name,_id = "",_CPU,_MemorySize,_DiskSize,_Note,_Purpose, _Stereotype,Vendor;
  public Node(string p_id) {this._name = p_id;}
  public string id {get { return _id;}
  public string name{get {return _name;} set {_name = value;}}
  public string CPU {get { return _CPU;} set {_CPU = value;}}
  public string MemorySize{get {return _MemorySize;}
  set {_MemorySize = value;}}
  public string DiskSize {get {return _DiskSize;}set {_DiskSize = value;}}
  public string Notes{get {return _Notes;}set {_Notes = value;}}
  public string Purpose{get {return _Purpose;} set {_Purpose = value;}}
  public string Stereotype {get {return _Stereotype;} set {_Stereotype = value;}}
  public string Vendor {get {return _Vendor;} set {_Vendor = value;}}
 }
}


  我并沒有提供示例3和輸出結果,因為它幾乎和示例4的完全相同。(列表5列出了示例3的完整的源代碼。)
 四、 示例4-添加繼承

  在最后的示例中,我從一個Node類繼承了結點實例。以前,我們每次只分析一個結點并對其進行遍歷。Node實例描述了存在于UML結點和硬件之間的關系。Nodes給了我們一種從實例中抽象出公共元素的方法。

   為此,有兩種不同的方法。第一種方法是使用Nodes來描述一個通用硬件平臺。可以設想這樣的情形:我為一家公司工作,該公司想針對它們所有的方法(多 么奇怪!)訂購相同的計算機配置。可以用一個結點來描述典型的計算機配置,然后該結點又會有多個結點實例。這將節省大量的輸入時間!另外一種方法是在軟件 架構師通知基礎構件小組怎樣分發組件的情形。該結點用針對于每個層的本地名字來描述不同的層。至于這些如何映射到實際的硬件是由結點實例所決定的而且由基 礎構件小組所創建。?

  在該示例中(見圖6),我展示了一個通用結點-"Fleet Management",它具有可以添加到它上面的組件。在一個多層系統中,Fleet Management是由軟件架構師來定義成一個分離的層。為了說明問題,我可能還要應用"Purpose"標簽。我有兩個結點實例,"Trucks"和 "Persons",它們由基礎構件小組來定義以把該層分成兩個方法。既然"Trucks"和"Persons"是完全不同的兩個域,那么架構師介入其中 并分解之是十分安全的。方法名字上還標記有":Fleet Management",以指明它們是在Fleet Management結點中實現的。
?


圖6.Trucks與Persons結點實例都繼承自Fleet Management結點。


   在這個示例中,沒有用于繼承的標簽,但是可能在另外的圖上存在一些其它關系-它們會連接到該結點實例上。

  我又一次重構了main程序以打印出所有的,包括每一個結點實例派生的(tNode.classname)結點標簽,還有結點的ID(tNode.classifier)。
?

public static void Main(string[] args)
{
 Hashtable mainHash;
 IDictionaryEnumerator ienum;
 Node tNode;
 string name = ReadString("Please enter the XMI filename : ");
 NodeParse np = new NodeParse(name);
 mainHash = np.getNodes();
 ienum = mainHash.GetEnumerator();
 while (ienum.MoveNext()){
  tNode = (Node)ienum.Value;
  System.Console.WriteLine("Node = " + tNode.name);
  //Add "if (tNode. != null)" for each Writeline()?
  System.Console.WriteLine(" CPU = " + tNode.CPU);
  System.Console.WriteLine(" DiskSize = " + tNode.DiskSize);
  System.Console.WriteLine(" MemorySize = " + tNode.MemorySize);
  System.Console.WriteLine(" Purpose = " + tNode.Purpose);
  System.Console.WriteLine(" Notes = " + tNode.Notes);
  System.Console.WriteLine("Node refers to = " + tNode.classname);
  System.Console.WriteLine("Node addr is " + tNode.classifier);
  System.Console.WriteLine();
 }
 System.Console.ReadLine();
}


  類名和類標志符指明該結點實例繼承自哪些結點。在XMI中,這是被象一個模板(就象一個封裝在結點元素中的元素)一樣描述的。

   現在我將使用一個開關語句來檢查"ModelElement.taggedValue",而代之以ModelElement.Stereotype,查 找"TaggedValue"元素(存在類名和類標志符上皆獨立的元素),并把它們添加到結點對象上。在此,我再次使用了分析idiom。這些代碼可以在 列表3中找到。


圖7.Trucks和Persons:示例4的最后輸出,Trucks和Persons各有一個它們可以參考的結點并且每個結點都有一個唯一的ID。

  圖7顯示示例4最后的輸出。

  五、 總結
?

  在本文中,我討論了可以從圖中讀取硬件資產的方法。還討論了讀取名字、模板、屬性以及讀取結點之間及結點實例(繼承)之間的關系。盡管我沒有給出把這種信息放入數據庫中的顯式代碼,我將在后面的文章中討論這些技術-當然不止是添加信息到數據庫中。

?

登錄樂搏學院官網http://www.learnbo.com/

或關注我們的官方微博微信,還有更多驚喜哦~


?

本文出自 “青峰” 博客,轉載請與作者聯系!

轉載于:https://my.oschina.net/learnbo/blog/829239

總結

以上是生活随笔為你收集整理的用C#+XMI技术进行UML模型捕获的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。