如何在一个XML中插入序列化的类

如何在一个XML中插入序列化的类,第1张

using (var ms = new MemoryStream())

{

ClassA tryXml = new ClassA {Key = "A", Value = "1"}

XmlSerializer serializer = new XmlSerializer(typeof (ClassA))

serializer.Serialize(ms, tryXml)

var xmlClass = new XmlDocument()

xmlClass.LoadXml(Encoding.UTF8.GetString(ms.ToArray()))

var xmlDocument = new XmlDocument()

xmlDocument.Load("C:\\temp\\TryXml.xml")

XmlElement element = xmlDocument.CreateElement("ClassA")

element.InnerXml = xmlClass.DocumentElement.InnerXml

xmlDocument.SelectSingleNode("/configuration").AppendChild(element)

xmlDocument.Save("C:\\temp\\TryXml.xml")

前阵子在写LINQ Douban的时候碰到关于XML序列化的场景 通过Douban api添加和更新数据的时候都需要Post一个xml entry 如

添加活动(xml中用%%括起来的部分是需要填写的部分 为了精简删除了xmlns)

view sourceprint? <?xml version= encoding= UTF ?>

<entry>

   <title>%title%</title>

   <category scheme= term=

   <content>%Content%</content>

   <db:attribute name= invite_only >%IsInviteOnly%</db:attribute>

   <db:attribute name= can_invite >%CanInvite%</db:attribute>

   <gd:when endTime= %Duration End% startTime= %Duration Start% />

   <gd:where valueString= %Where% />

</entry>

一下子能想到的方法有两个——通过XmlSerializer或在entity class上实现IXmlSerializable接口来实现 但很快发现有几个问题没法解决

XmlSerializer不支持泛型集合的序列化 而我在定义entity class时用了不少IList和IDictionary 如db:attribute我就定义成IDictionary

XmlSerializer只能生成完整的element和attribute 像上面那段xml里<category>节点term属性里变化的只有后面%Category%部分 这就没法生成了

存在添加和更新的post内容不一样的情况 这就意味着同一个entity class 存在多种序列化方案

douban的xml entry格式可能会更改 而我不希望因此而更改代码

想来想去 最好的方法是通过XML模板+反射(简称XMl模板替换)来生成了 就像上面的xml etnry里面%%括起来的部分 替换掉就可以了 这样可以解决上述的四个问题 除了提供和XMLSerializer功能相同的序列化之外 XML模板替换还要满足下面这些要求

可以序列化实现IEnumerable的集合 这是最常用的集合 当然大多数的泛型集合也是应用了IEnumerable的

提供更灵活的替换 XmlSerializer实现的序列化顺序是 A(B(c)B)A 对于子对象的序列化只能是嵌套的模式 而XML模板替换可以实现任何层次的替换

为每种类型的对象提供通用的序列化方式 不需要任何Attribute定义 不需要修改对象的定义 对于给定的object和XML模板 通过发射获取属性值进行XML替换后生成XML内容 对于相同的object 提供不同的XML模板就能生成不同的XML

通过修改XML模板即可修改序列化结果

下面给出一个修改过的RSS的XML模板 这次Code Fun的目的是在最后实现这个模板的替换 并且完成一个能够实现上述功能的Helper class

特别的地方

<category>节点 通过 可访问子对象的属性 如果你希望获取Domain的长度可以写成 %Category Domain Length%

<noReplacement>节点 该节点不包含任何替换信息 当进行替换处理时应当忽略

<skipHours>节点 SkipHours是一个List<int>集合 我们希望能够根据SkipHours的值 展开多个<hour>节点

<as:scope>节点 <scope>是模板定义 声明<scope>节点内包含的子节点在Channel Items对象的作用域中 所有%%(不包括% /Category Name%)的属性都是对Items对象的属性访问 由于此处Items对象是List<RssItem>集合 所以将循环生成多个<item>Scope的含义类似于程序域 支持多个scope的嵌套 Scope定义不会出现在最后生成的xml中

<channelCategory>节点 <channelCategory>节点在Items的作用域中 但我们可以通过 / 访问外部scope的属性 类似dos文件路径 如果要访问上上级scope 则是 / / % /Category Name%表示访问Channel对象的Category属性的Name属性

view sourceprint? <channel>

     <title>%Title%</title>

     <link>%Link%</link>

     <category domain= %Category Domain% >%Category Name%</category>

     <noRelacement>不需要替换</noRelacement>

     <skipHours>

       <hour>%SkinHours%</hour>

     </skipHours>

     <as:scope xmlns:as= name= Items type= AllSharing Xml Rss RssItem >

       <item>

         <title>%Title%</title>

         <link>%Link%</link>

         <description>%Description%</description>

         <channelCategory>% /Category Name%</channelCategory>

       </item>

     </as:scope>

   </channel>

view sourceprint?

相关class定义

view sourceprint? public class RssChannel

{

     public string Title { getset}

         public string Link { getset}

         public RssCategory Category { getset}

         public IList<int>SkinHours { getset}

         public IList<RssItem>Items { getset}

}

public class RssItem

{

         public string Title { getset}

         public string Link { getset}

}

public class RssCategory

{

     public string Domain { getset}

         public string Name { getset}

}

下面将一步步讨论如何实现XML模板的替换 会给出部分代码或伪代码 完整的代码在文章最后会给出下载

一 分析XML模板

XML模板替换最终要是要回归到用正则表达式替换掉所有的%% 但由于我们要处理的模板包括域 子属性访问 循环的信息 所以这不是仅仅的Regex Replace就可以搞定的 分析XML模板 就是要遍历XML模板生成一个Scope树 上面的XML模板可以生成下面的Scope树

XML模板中包含了的三种我们需要处理的元素

包含%%的XML Attribute

包含%%的XML Element以及Element的子节点

Scope节点

从上面的Scope树可以看出 像<noReplace>这样不需要替换的XML element或XML attribute被当作常量 没有包括在Scope树中

在Helper Class中分析Scope树的方法

view sourceprint? var scope = XmlTemplateScope Compile(xmlPath entityType)

xmlPath是模板文件的路径 entityType是Scope树用于分析的对象类型

二 对给定的object 生成XML

这里用了LINQ XML 首先用XDocument Load(xmlPath)的到XML模板文件的XDocument 然后根据Scope树对XDocument上的节点进行属性值替换 节点Value替换 增加节点(Repeat的节点) 幸运的是XDocument比XmlDocument方便太多了 实现起来非常快

在Helper Class中生成XML的方法

view sourceprint? var template = new XmlTemplate(xmlPath scope)

Console WriteLine(template Translate(entityObj))

template是线程安全的 根据需要你可以Cache起来 不用每次都生成Scope树 这样或许会减少部分性能消耗(未测试)

完整的代码如下(包含在Demo中)

view sourceprint? var channel = new RssChannel()

channel Title = this is channel title

channel Link =

channel Description = this is channel description

channel Category = new RssCategory()

channel Category Domain =

channel Category Name = this is channel category

channel SkipHours Add( )

channel SkipHours Add( )

channel SkipHours Add( )

channel Items Add(new RssItem { Title= Item Link= Link Description= Des })

channel Items Add(new RssItem { Title = Item Link = Link Description = Des })

channel Items Add(new RssItem { Title = Item Link = Link Description = Des })

var path = Path Combine(AppDomain CurrentDomain BaseDirectory rss xml )

var template = new XmlTemplate(

     path XmlTemplateScope Compile(path typeof(RssChannel)))

template Translate(channel) Dump()

生成XML如下

view sourceprint?    <channel>

     <title>this is channel title</title>

     <link>/link>

     <category domain= this >>this is channel category</cate

gory>

     <noRelacement>不需要替换</noRelacement>

     <skipHours>

       <hour></hour>

       <hour></hour>

       <hour></hour>

     </skipHours>

     <item>

       <title>Item </title>

       <link>Link </link>

       <description>Des </description>

       <channelCategory>this is channel category</channelCategory>

     </item>

     <item>

       <title>Item </title>

       <link>Link </link>

       <description>Des </description>

       <channelCategory>this is channel category</channelCategory>

     </item>

     <item>

       <title>Item </title>

       <link>Link </link>

       <description>Des </description>

       <channelCategory>this is channel category</channelCategory>

     </item>

   </channel>

lishixinzhi/Article/program/net/201311/12717

给你个我写的用XML存配置的类。你自己看吧。 我看见你的第二题了。仔细看这个。简单的存储都有了

using System

using System.Collections.Generic

using System.Text

using System.Xml

using System.IO

using Microsoft.Win32

using System.Drawing

using System.Windows.Forms

namespace ChartFormat

{

class Config

{

#region 删除配置文件

/// <summary>

/// 删除配置文件

/// </summary>

/// <returns></returns>

public static bool DelConfig()

{

string m_strFullPath = ""

m_strFullPath = Directory.GetCurrentDirectory() + @"\" + "Config.config"

try

{

File.Delete(m_strFullPath)

return true

}

catch

{

return false

}

}

#endregion

#region 判断该路径文件是否存在 如果不存在则创建

/// <summary>

/// 判断该路径文件是否存在 如果不存在则创建

/// </summary>

/// <param name="m_strFullPath">路径</param>

public static void ConfigFile(string m_strFullPath)

{

StreamWriter sr = null

if (!System.IO.File.Exists(m_strFullPath))

{

try

{

sr = new StreamWriter(m_strFullPath)

sr.WriteLine("<?xml version=" + "\"" + "1.0" + "\"" + " encoding=" + "\"" + "utf-8" + "\"" + " ?>")

sr.WriteLine("<configuration>")

sr.WriteLine("<appSettings>")

sr.WriteLine("<add key=" + "\"" + "NameColour" + "\"" + " value=" + "\"" + "Blue" + "\"" + "/>")

sr.WriteLine("<add key=" + "\"" + "InfoColour" + "\"" + " value=" + "\"" + "Black" + "\"" + "/>")

sr.WriteLine("<add key=" + "\"" + "IsURL" + "\"" + " value=" + "\"" + "0" + "\"" + "/>")

sr.WriteLine("<add key=" + "\"" + "IsEmail" + "\"" + " value=" + "\"" + "0" + "\"" + "/>")

sr.WriteLine("<add key=" + "\"" + "IsMoveTime" + "\"" + " value=" + "\"" + "1" + "\"" + "/>")

sr.WriteLine("<add key=" + "\"" + "IsMove" + "\"" + " value=" + "\"" + "1" + "\"" + "/>")

sr.WriteLine("<add key=" + "\"" + "MoveValue" + "\"" + " value=" + "\"" + "3" + "\"" + "/>")

sr.WriteLine("</appSettings>")

sr.WriteLine("</configuration>")

sr.Close()

}

catch (Exception e)

{

sr.Close()

MessageBox.Show("创建配置文件错误!", "信息", MessageBoxButtons.OK, MessageBoxIcon.Question)

}

finally

{

if (sr != null)

{

sr.Close()

}

}

}

}

#endregion

#region 更新Config文件

/// <summary>

/// 更新Config文件

/// </summary>

/// <param name="p_strKey">键</param>

/// <param name="p_strValue">值</param>

public static void UpdateConfig(string p_strKey, string p_strValue)

{

try

{

string m_strFullPath = ""

XmlDocument xmlDoc = new XmlDocument()

m_strFullPath = Directory.GetCurrentDirectory() + @"\" + "Config.config"

ConfigFile(m_strFullPath)

if (File.Exists(m_strFullPath))

{

//处理数据文件为只读的情况

if ((File.GetAttributes(m_strFullPath) &FileAttributes.ReadOnly) == FileAttributes.ReadOnly)

{

File.SetAttributes(m_strFullPath, File.GetAttributes(m_strFullPath) &(~FileAttributes.ReadOnly))

}

}

xmlDoc.Load(m_strFullPath)

XmlNodeList nodeList = xmlDoc.SelectSingleNode("/configuration/appSettings").ChildNodes

foreach (XmlNode xn in nodeList)//遍历所有子节点

{

XmlElement xe = (XmlElement)xn

if (xe.GetAttribute("key").IndexOf(p_strKey) != -1)

{

xe.SetAttribute("value", p_strValue)

}

}

xmlDoc.Save(m_strFullPath)

//fs.Close()

}

catch (System.NullReferenceException NullEx)

{

throw NullEx

}

catch (Exception ex)

{

throw ex

}

}

#endregion

}

public class ConfigInfo

{

private string strNameColor =ColorTranslator.ToHtml( System.Drawing.Color.Blue)

private string strInfoColor = ColorTranslator.ToHtml(System.Drawing.Color.Black)

private string strIsURL = "1"

private string strIsEmail = "1"

private string strIsMove = "1"

private string strMoveValue = "3"

private string strIsMoveTime = "1"

/// <summary>

/// 是否移除空格

/// </summary>

public bool IsMoveTime

{

get

{

if (strIsMoveTime == "1")

{

return true

}

else

{

return false

}

}

set

{

if (value)

{

strIsMoveTime = "1"

}

else

{

strIsMoveTime = "0"

}

}

}

/// <summary>

/// 缩进空格

/// </summary>

public decimal MoveValue

{

get

{

return Convert.ToDecimal(strMoveValue)

}

set

{

strMoveValue = value.ToString()

}

}

/// <summary>

/// 是否缩进

/// </summary>

public bool IsMove

{

get

{

if (strIsMove == "1")

{

return true

}

else

{

return false

}

}

set

{

if (value)

{

strIsMove = "1"

}

else

{

strIsMove = "0"

}

}

}

/// <summary>

/// 邮件是否可以点击

/// </summary>

public bool IsEmail

{

get

{

if (strIsEmail == "1")

{

return true

}

else

{

return false

}

}

set

{

if (value)

{

strIsEmail = "1"

}

else

{

strIsEmail = "0"

}

}

}

/// <summary>

/// 网页是否可以点击

/// </summary>

public bool IsURL

{

get

{

if (strIsURL== "1")

{

return true

}

else

{

return false

}

}

set

{

if (value)

{

strIsURL = "1"

}

else

{

strIsURL = "0"

}

}

}

/// <summary>

/// 消息颜色

/// </summary>

public Color InfoColor

{

get

{

return ColorTranslator.FromHtml(strInfoColor)

}

set

{

strInfoColor = ColorTranslator.ToHtml(value)

}

}

/// <summary>

/// 信息颜色

/// </summary>

public Color NameColor

{

get

{

return ColorTranslator.FromHtml(strNameColor)

}

set

{

strNameColor = ColorTranslator.ToHtml(value)

}

}

public ConfigInfo()

{

string m_strFullPath = ""

XmlDocument xmlDoc = new XmlDocument()

m_strFullPath = Directory.GetCurrentDirectory() + @"\" + "Config.config"

Config.ConfigFile(m_strFullPath)

xmlDoc.Load(m_strFullPath)

XmlNodeList nodeList = xmlDoc.SelectSingleNode("/configuration/appSettings").ChildNodes

foreach (XmlNode xn in nodeList)//遍历所有子节点

{

XmlNodeReader objNdRd = new XmlNodeReader(xn)

while (objNdRd.Read())

{

if (objNdRd.GetAttribute("key").IndexOf("NameColour") != -1)

{

this.strNameColor = objNdRd.GetAttribute("value")

}

if (objNdRd.GetAttribute("key").IndexOf("InfoColour") != -1)

{

this.strInfoColor = objNdRd.GetAttribute("value")

}

if (objNdRd.GetAttribute("key").IndexOf("IsURL") != -1)

{

this.strIsURL = objNdRd.GetAttribute("value")

}

if (objNdRd.GetAttribute("key").IndexOf("IsEmail") != -1)

{

this.strIsEmail = objNdRd.GetAttribute("value")

}

if (objNdRd.GetAttribute("key").IndexOf("IsMove") != -1)

{

this.strIsMove = objNdRd.GetAttribute("value")

}

if (objNdRd.GetAttribute("key").IndexOf("MoveValue") != -1)

{

this.strMoveValue = objNdRd.GetAttribute("value")

}

}

}

}

public void Update()

{

Config.DelConfig()

string m_strFullPath = ""

XmlDocument xmlDoc = new XmlDocument()

m_strFullPath = Directory.GetCurrentDirectory() + @"\" + "Config.config"

Config.ConfigFile(m_strFullPath)

Config.UpdateConfig("NameColour", strNameColor)

Config.UpdateConfig("InfoColour", strInfoColor)

Config.UpdateConfig("IsURL", strIsURL)

Config.UpdateConfig("IsEmail", strIsEmail)

Config.UpdateConfig("IsMove", strIsMove)

Config.UpdateConfig("MoveValue", strMoveValue)

}

}

}


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/bake/11760289.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-18
下一篇 2023-05-18

发表评论

登录后才能评论

评论列表(0条)

保存