如何将XSLT生成的XML转换为结构化数据表并实现反向还原?
如何将XSLT生成的XML转换为结构化数据表并实现反向还原?
我明白你现在的困扰——把这种嵌套结构的XML转成规整的DataTables确实容易摸不着头绪,尤其是它还来自4张原始表的XSLT转换结果。咱们一步步来拆解解决:
一、把现有XML解析为结构化DataTables
你的XML里有三种典型结构,咱们分别处理:
1. 单条记录型(如TableName0)
这种是单个<obj>节点对应一张表的单行数据,子节点的name属性是列名,val属性是值。直接遍历子节点生成列和行即可:
// 加载XML文档 XmlDocument doc = new XmlDocument(); doc.Load("your-target.xml"); // 处理TableName0 XmlNode table0Node = doc.SelectSingleNode("//obj[@name='TableName0']"); DataTable table0 = new DataTable("TableName0"); // 先添加所有列 foreach (XmlNode fieldNode in table0Node.ChildNodes) { string colName = fieldNode.Attributes["name"].Value; // 根据节点类型(int/str)指定列的数据类型 Type colType = fieldNode.Name == "int" ? typeof(int) : typeof(string); table0.Columns.Add(colName, colType); } // 填充单行数据 DataRow row0 = table0.NewRow(); foreach (XmlNode fieldNode in table0Node.ChildNodes) { string colName = fieldNode.Attributes["name"].Value; string val = fieldNode.Attributes["val"].Value; row0[colName] = fieldNode.Name == "int" ? int.Parse(val) : val; } table0.Rows.Add(row0);
2. 多行对象型(如TableName1)
外层<list>对应表,内部每个<obj>是一行数据,注意不同行可能有不同的列(比如RowOfData2比RowOfData1多3列),所以要先收集所有可能的列名,再逐行填充:
// 处理TableName1 XmlNodeList table1Objs = doc.SelectNodes("//list[@name='TableName1']/obj"); DataTable table1 = new DataTable("TableName1"); HashSet<string> allColNames = new HashSet<string>(); // 第一步:遍历所有行,收集完整的列名集合 foreach (XmlNode objNode in table1Objs) { foreach (XmlNode fieldNode in objNode.ChildNodes) { allColNames.Add(fieldNode.Attributes["name"].Value); } } // 添加所有列到DataTable(这里先统一用string类型,你可以根据实际节点类型调整) foreach (string colName in allColNames) { table1.Columns.Add(colName); } // 第二步:逐行填充数据 foreach (XmlNode objNode in table1Objs) { DataRow row = table1.NewRow(); foreach (XmlNode fieldNode in objNode.ChildNodes) { string colName = fieldNode.Attributes["name"].Value; // 处理<int>/<str>的val属性,以及<ref>的href属性 string val = fieldNode.Attributes["val"]?.Value ?? fieldNode.Attributes["href"]?.Value; row[colName] = val; } table1.Rows.Add(row); }
3. 嵌套列表型(如TableName2)
外层<list>是表,内层<list>是行,行内的<int>节点是列(name属性为列名),同样先收集列名再填充:
// 处理TableName2 XmlNodeList table2Rows = doc.SelectNodes("//list[@name='TableName2']/list"); DataTable table2 = new DataTable("TableName2"); HashSet<string> table2ColNames = new HashSet<string>(); // 收集所有列名 foreach (XmlNode rowNode in table2Rows) { foreach (XmlNode fieldNode in rowNode.ChildNodes) { table2ColNames.Add(fieldNode.Attributes["name"].Value); } } // 添加列(这里都是int类型,可根据实际调整) foreach (string colName in table2ColNames) { table2.Columns.Add(colName, typeof(int)); } // 填充每一行数据 foreach (XmlNode rowNode in table2Rows) { DataRow row = table2.NewRow(); foreach (XmlNode fieldNode in rowNode.ChildNodes) { string colName = fieldNode.Attributes["name"].Value; int val = int.Parse(fieldNode.Attributes["val"].Value); row[colName] = val; } table2.Rows.Add(row); }
二、反向还原:从XML转回原始4张数据表
这里要明确一个关键点:XSLT是单向转换工具,它只能把原始XML/数据表转成你现在拿到的XML,没法自动反向转换。不过有几个可行的思路:
- 写反向XSLT:如果原XSLT的转换逻辑很清晰(比如只是把原始表的字段映射成当前的
<obj>/<list>结构),你可以编写一个反向的XSLT,把当前的XML转换回原始数据表的XML结构,然后再导入DataSet生成原始表。 - 手动映射结构:如果你能拿到原始4张表的结构定义(列名、数据类型、关联关系),可以直接基于当前XML的内容,按照对应关系把数据填充到原始结构的DataTables里——逻辑和前面解析XML的思路类似,只是列名和结构要对应原始表。
- 利用原XSLT的映射信息:如果原XSLT里保留了字段的原始映射(比如注释或者特殊属性),那反向会更简单,但从你给出的XML来看没有这类信息,所以得靠人工梳理结构对应关系。
总的来说,先根据XML的三种结构分别解析成规整的DataTables;反向还原的核心是还原原始表的结构映射,要么写反向XSLT,要么手动对应填充。
备注:内容来源于stack exchange,提问作者Jason Shoulders
相关产品推荐
相关产品推荐

