从这篇开始将正式讲解整个重要部分的实现细节,本篇讲解Pdm文件的解析。其实PDM文件就是XML文件,可以用Editplus或者VS打开查看。了解到这一点之后大家就能猜到,可以用解析XML的方式读取PDM文件了。
PDM文件结构及在本工具的存储方式
下面看看用Editplus读取出来的XML,这里我只关注Table节点,这是一个表的最小节点了。
<o:Table Id="o97"> <a:ObjectID>41144D16-B6B3-43CD-8B36-57CBAFB26654</a:ObjectID> <a:Name>预算资源面积月事实表</a:Name> <a:Code>y_FactYsRoomAreaMonth</a:Code> <a:CreationDate>1366118213</a:CreationDate> <a:Creator>huzhiwen</a:Creator> <a:ModificationDate>1396403208</a:ModificationDate> <a:Modifier>gongw</a:Modifier> <a:TotalSavingCurrency/> <c:Columns> <o:Column Id="o361"> <a:ObjectID>F03D6EA9-183A-4B6A-BD52-7B711572AA45</a:ObjectID> <a:Name>ID</a:Name> <a:Code>ID</a:Code> <a:CreationDate>1366118213</a:CreationDate> <a:Creator>huzhiwen</a:Creator> <a:ModificationDate>1381212250</a:ModificationDate> <a:Modifier>huzw</a:Modifier> <a:DataType>bigint</a:DataType> <a:Identity>1</a:Identity> <a:Mandatory>1</a:Mandatory> </o:Column> </c:Columns> <c:Keys> <o:Key Id="o380"> <a:ObjectID>F9089FCD-D9E9-4FB0-92F3-B7268D49526D</a:ObjectID> <a:Name>PK_Z_DIMROOMMONTH</a:Name> <a:Code>PK_Z_DIMROOMMONTH</a:Code> <a:CreationDate>1366118213</a:CreationDate> <a:Creator>huzhiwen</a:Creator> <a:ModificationDate>1366118213</a:ModificationDate> <a:Modifier>huzhiwen</a:Modifier> <c:Key.Columns> <o:Column Ref="o361"/> </c:Key.Columns> </o:Key> </c:Keys> <c:PrimaryKey> <o:Key Ref="o380"/> </c:PrimaryKey> <c:ClusterObject> <o:Key Ref="o380"/> </c:ClusterObject> </o:Table>
可以看到这些节点都是带命名空间,所以我们解析这段XML的时候需要加上命名空间。表的<a:Name>(中文名称),<a:Code>(表名),<c:Columns>是所有列节点集合,具体到每一列的<o:Column>则有中文名称,英文名称,主键,是否空,默认值,是否自增等关键信息了。
参考上面的设计,添加了四个实体,ColumnInfo,TableInfo,PkKeyInfo,PhysicalDiagramInfo
PDM文件读取
1.加载XML
/// <summary> /// 读取xml文件返回XmlDocument对象 /// </summary> /// <returns>XmlDocument对象</returns> private XmlDocument GetXmlDom() { try { if (xmlDoc == null) { StreamReader sr = new StreamReader(_pdmPath); xmlDoc = new XmlDocument(); xmlDoc.LoadXml(ReplaceLowOrderASCIICharacters(sr.ReadToEnd())); } return xmlDoc; } catch (Exception ex) { throw ex; } }
2.设置XML的命名空间
/// <summary> /// 设置xml文件命名空间 /// </summary> /// <returns>XmlNamespaceManager</returns> private XmlNamespaceManager GetXmlNamespace() { XmlNamespaceManager xmlnsManager = new XmlNamespaceManager(GetXmlDom().NameTable); xmlnsManager.AddNamespace("a", "attribute"); xmlnsManager.AddNamespace("c", "collection"); xmlnsManager.AddNamespace("o", "object"); return xmlnsManager; }
3.从中XML读取表信息
/// <summary> /// 从中XML读取表信息 /// </summary> /// <returns> List</returns> public List<TableInfo> GetTableInfo() { try { XmlDocument xmlDoc = GetXmlDom(); XmlNamespaceManager xmlnsManager = GetXmlNamespace(); XmlNode xnTables = xmlDoc.SelectSingleNode("//" + "c:Tables", xmlnsManager); List<TableInfo> Tables = new List<TableInfo>(); foreach (XmlNode xnTable in xnTables.ChildNodes) { Tables.Add(GetTable(xnTable)); } return Tables; } catch (Exception ex) { throw ex; } }
/// <summary> /// 获取节点中表的信息 /// </summary> /// <param name="xnTable">xmlNode</param> /// <returns>表信息</returns> private TableInfo GetTable(XmlNode xnTable) { try { TableInfo mTable = new TableInfo(); XmlElement xe = (XmlElement)xnTable; mTable.TableID = xe.GetAttribute("Id"); XmlNodeList xnTProperty = xe.ChildNodes; foreach (XmlNode xnP in xnTProperty) { switch (xnP.Name) { //表的ID case "a:ObjectID": mTable.TableObjectID = xnP.InnerText; break; //表的中文名称 case "a:Name": mTable.Name = xnP.InnerText; break; //表的英文名称 case "a:Code": mTable.Code = xnP.InnerText; break; //表的描述 case "a:Comment": mTable.Comment = xnP.InnerText; break; //表的列信息 case "c:Columns": InitColumns(xnP, mTable); break; //表的主键信息 case "c:Keys": InitKeys(xnP, mTable); break; default: break; } } if (string.IsNullOrEmpty(mTable.Comment)) { mTable.Comment = mTable.Name; } if (mTable.ListPkKeyInfo != null && mTable.ListPkKeyInfo.Count > 0) { foreach (PkKeyInfo pkInfo in mTable.ListPkKeyInfo) { ColumnInfo info = mTable.ListColumnInfo.Single(c => c.ColumnId == pkInfo.ColumnId); pkInfo.Name = info.Code; info.PK = true; mTable.PkKeyNameList = mTable.PkKeyNameList + pkInfo.Name + ","; } } //杜冬军2014-05-16 修改没有主键 生成SQL有问题的BUG V1.4 else { mTable.ListPkKeyInfo=new List<PkKeyInfo>(); } if (!string.IsNullOrEmpty(mTable.PkKeyNameList)) { mTable.PkKeyNameList = mTable.PkKeyNameList.Substring(0, mTable.PkKeyNameList.Length - 1); } return mTable; } catch (Exception ex) { throw ex; } }
4.读取列信息
/// <summary> /// 获取列信息 /// </summary> /// <param name="xnColumn">列节点</param> /// <returns>列信息</returns> private ColumnInfo GetColumn(XmlNode xnColumn) { ColumnInfo mColumn = new ColumnInfo(); XmlElement xe = (XmlElement)xnColumn; mColumn.ColumnId = xe.GetAttribute("Id"); XmlNodeList xnCProperty = xe.ChildNodes; foreach (XmlNode xnP in xnCProperty) { switch (xnP.Name) { //列ID case "a:ObjectID": mColumn.ColumnObjectId = xnP.InnerText; break; //列中文名称 case "a:Name": mColumn.Name = xnP.InnerText; break; //列英文名称 case "a:Code": mColumn.Code = xnP.InnerText; break; //列描述 case "a:Comment": mColumn.Comment = xnP.InnerText; break; //列数据类型 case "a:DataType": mColumn.DataTypeStr = xnP.InnerText.Replace("(", "(").Replace(")", ")"); mColumn.DataType = Common.GetColumnDataType(mColumn.DataTypeStr); mColumn.Width = Common.GetColumnWidth(mColumn.DataTypeStr); break; //列宽度 case "a:Length": mColumn.Length = xnP.InnerText; break; //列是否自增 case "a:Identity": mColumn.Identity = Common.ConvertToBooleanPG(xnP.InnerText); break; //列默认值 case "a:DefaultValue": mColumn.DefaultValue = xnP.InnerText; break; //列是否可为空 case "a:Mandatory": mColumn.Nullable = Common.ConvertToBooleanPG(xnP.InnerText); break; default: break; } } if (string.IsNullOrEmpty(mColumn.Comment)) { mColumn.Comment = mColumn.Name; } if (string.IsNullOrEmpty(mColumn.DefaultValue)) { mColumn.DefaultValue = ""; } return mColumn; }
其它信息操作可以查看源代码里面的PDMReader.cs文件
XML文件操作增删改查
PDM文件操作完毕,大家可以发现归根到底就是XML的增删改查操作,读取XML文件用Xpth比较方便。
我做了一个小例子供大家参考:XmlDemo
public void Read() { XmlNodeList xmlNodeList = null; xmlNodeList = XmlDoc.SelectNodes("/root/item"); Console.WriteLine("遍历item节点"); foreach (XmlNode xmlNode in xmlNodeList) { Console.WriteLine("item节点的RoomInfo属性读取:{0}", xmlNode.Attributes["RoomInfo"].Value); Console.WriteLine("item节点的RoomInfo的值读取:{0}", xmlNode.InnerText); } Console.WriteLine("遍历items下的item节点"); xmlNodeList = XmlDoc.SelectNodes("/root/items/item"); foreach (XmlNode xmlNode in xmlNodeList) { Console.WriteLine("item节点的RoomInfo属性读取:{0}", xmlNode.Attributes["RoomInfo"].Value); Console.WriteLine("item节点的RoomInfo的值读取:{0}", xmlNode.InnerText); } Console.WriteLine("遍历第一个items下的item节点"); xmlNodeList = XmlDoc.SelectNodes("/root/items[@id='item1']/item"); foreach (XmlNode xmlNode in xmlNodeList) { Console.WriteLine("item节点的RoomInfo属性读取:{0}", xmlNode.Attributes["RoomInfo"].Value); Console.WriteLine("item节点的RoomInfo的值读取:{0}", xmlNode.InnerText); } Console.WriteLine("遍历第二个items下的Group下的item节点"); xmlNodeList = XmlDoc.SelectNodes("/root/items[@id='item2']/Group[@id='g1']/item"); foreach (XmlNode xmlNode in xmlNodeList) { Console.WriteLine("item节点的RoomInfo属性读取:{0}", xmlNode.Attributes["RoomInfo"].Value); Console.WriteLine("item节点的RoomInfo的值读取:{0}", xmlNode.InnerText); } }
public void Update() { Console.WriteLine("修改所有的item节点RoomInfo的属性的值为123"); XmlNodeList xmlNodeList = null; xmlNodeList = XmlDoc.SelectNodes("/root/item"); foreach (XmlNode xmlNode in xmlNodeList) { xmlNode.Attributes["RoomInfo"].Value = "123"; } Console.WriteLine("修改所有的item节点的值为123"); xmlNodeList = XmlDoc.SelectNodes("/root/item"); foreach (XmlNode xmlNode in xmlNodeList) { xmlNode.InnerText = "123"; } Console.WriteLine(XmlDoc.InnerXml); }
public void Delete() { Console.WriteLine("删除所有的item节点"); XmlNodeList xmlNodeList = null; xmlNodeList = XmlDoc.SelectNodes("/root/item"); foreach (XmlNode xmlNode in xmlNodeList) { xmlNode.ParentNode.RemoveChild(xmlNode); } Console.WriteLine("删除所有的items下的子节点"); xmlNodeList = XmlDoc.SelectNodes("/root/items"); foreach (XmlNode xmlNode in xmlNodeList) { xmlNode.RemoveAll(); } Console.WriteLine(XmlDoc.InnerXml); }
public void Add() { Console.WriteLine("item节点添加test=123属性"); XmlNodeList xmlNodeList = null; XmlAttribute xmlAttribute = null; xmlNodeList = XmlDoc.SelectNodes("/root/item"); foreach (XmlNode xmlNode in xmlNodeList) { xmlAttribute = XmlDoc.CreateAttribute("test"); xmlAttribute.Value = "123"; xmlNode.Attributes.Append(xmlAttribute); } Console.WriteLine("item节点添加子节点<test name='123'>"); xmlNodeList = XmlDoc.SelectNodes("/root/item"); XmlElement xmlNewNode = null; foreach (XmlNode xmlNode in xmlNodeList) { xmlNewNode = XmlDoc.CreateElement("test"); xmlNewNode.SetAttribute("name", "123"); xmlNewNode.InnerText = "123"; xmlNode.AppendChild(xmlNewNode); } XmlDoc.Save("C:\\123.xml"); Console.WriteLine(XmlDoc.InnerXml); }
工具源代码下载
目前总共有经过了七个版本的升级,现在提供最新版本的下载地址
数据字典生成工具V2.0安装程序 | 最新安装程序 | |
数据字典生成工具源代码 | 最新源代码 | |
http://code.taobao.org/svn/DataDicPub | SVN最新源码共享地址 |
学习使用
如果你使用了该工具,或者想学习该工具,欢迎加入这个小组,一起讨论数据字典生成工具、把该工具做的更强,更方便使用,一起加入147425783 QQ群。
更多数据字典生成工具资料请点击数据字典生成工具专题。