从这篇开始将正式讲解整个重要部分的实现细节,本篇讲解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 > )
{
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(, mTable.PkKeyNameList.Length - );
}
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 = "";
}
Console.WriteLine("修改所有的item节点的值为123");
xmlNodeList = XmlDoc.SelectNodes("/root/item");
foreach (XmlNode xmlNode in xmlNodeList)
{
xmlNode.InnerText = "";
}
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 = "";
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", "");
xmlNewNode.InnerText = "";
xmlNode.AppendChild(xmlNewNode);
}
XmlDoc.Save("C:\\123.xml");
Console.WriteLine(XmlDoc.InnerXml);
}
工具源代码下载
目前总共有经过了七个版本的升级,现在提供最新版本的下载地址
数据字典生成工具V2.0安装程序 | 最新安装程序 | |
数据字典生成工具源代码 | 最新源代码 | |
http://code.taobao.org/svn/DataDicPub | SVN最新源码共享地址 |
学习使用
如果你使用了该工具,或者想学习该工具,欢迎加入这个小组,一起讨论数据字典生成工具、把该工具做的更强,更方便使用,一起加入147425783 QQ群。
更多数据字典生成工具资料请点击数据字典生成工具专题。