【问题标题】:xml to a nested dictionary strucurexml 到嵌套字典结构
【发布时间】:2014-07-17 20:02:59
【问题描述】:

我有一个这样的 xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<Admin>
  <Name>function1</Name>
  <Id>1</Id>
  <Value>True</Value>
  <Name>function2</Name>
  <Id>2</Id>
  <Value>False</Value>
  .
  .
  .
  <Name>functionN</Name>
  <Id>N</Id>
  <Value>False</Value>
</Admin>

我想将此文件加载到这样的字典结构中:

Dictionary<AccessPoint, bool>

AccessPoint 是一个类:

public class AccessPoint
{
  public int    Id   { get; set; }
  public string Name { get; set; }
}

那么我怎样才能将每段 xml 以较短的代码放在正确的位置呢?

这是我到目前为止所做的:

using (XmlReader reader = new XmlTextReader(path))
{
  XmlDocument doc = new XmlDocument();
  doc.Load(reader);

  XmlNodeList nodeList = doc.ChildNodes;

  foreach (XmlNode node in nodeList)
  {
    var xmlValue = new Dictionary<string, string>();

    foreach (XmlNode child in node.ChildNodes)
    {
      xmlValue[child.LocalName] = child.InnerText;
    }

    entityInfo.Add(xmlValue);

  }
}

但是,entityInfo 只收集 xml 文件的最后一个单位值:

{[Value, False]}
{[Id, N]}
{[Name, FunctionN]}

【问题讨论】:

  • 我建议您查看 XDocumentXMLDocument 类。 LINQ to XML 也是一个选项。你能展示一下你到目前为止所做的尝试吗?
  • 或者创建自己的字典类型(扩展Dictionary&lt;AccessPoint, bool&gt;)并实现接口IXmlSerializable

标签: c# xml dictionary


【解决方案1】:

您可能可以编写一个 XPath 查询来获得您想要的东西,但是如果您执行以下操作,那么获得您想要的东西可能会更容易(也更高效!):

class AccessPoint
{
  public string Name  { get ; set ; }
  public int    Id    { get ; set ; }
  public bool   Value { get ; set ; }
}

static IEnumerable<AccessPoint> AccessPointsFromXml( XDocument doc )
{
  AccessPoint item = null ;

  foreach( XElement e in doc.Root.Elements() )
  {
    switch ( e.Name.LocalName )
    {
    case "Name" :
      if ( item != null ) yield return item ;
      item = new AccessPoint{ Name = e.Value , } ;
      break ;
    case "Id" :
      int id ;
      int.TryParse(e.Value,out id) ;
      if ( item == null ) item = new AccessPoint() ;
      item.Id = id ;
      break ;
    case "Value" :
      bool value ;
      bool.TryParse(e.Value,out value) ;
      if ( item == null ) item = new AccessPoint() ;
      item.Value = value ;
      break ;
    }
  }

  // take care of the last item (if there is one)
  if ( item != null ) yield return item ;

}

然后构建你的字典很容易:

string xml = @"
  <?xml version=""1.0"" encoding=""utf-8""?>
  <Admin>
    <Name>function1</Name>
    <Id>1</Id>
    <Value>True</Value>
    <Name>function2</Name>
    <Id>2</Id>
    <Value>False</Value>
    <Name>function3</Name>
    <Id>3</Id>
    <Value>False</Value>
  </Admin>
  ".Trim() ;

XDocument                    doc  = XDocument.Load( new StringReader(xml) ) ;
Dictionary<AccessPoint,bool> dict = AccessPointsFromXml(doc)
                                    .ToDictionary( x => x , x => x.Value )
                                    ;

编辑注意:

使用XmlDocument 代替XDocument 并没有太大的改变:

static IEnumerable<AccessPoint> AccessPointsFromXml( XmlDocument doc )
{
  AccessPoint item = null ;
  foreach( XmlElement e in doc.DocumentElement.ChildNodes )
  {
    switch ( e.LocalName )
    {
    case "Name" :
      if ( item != null ) yield return item ;
      item = new AccessPoint{ Name = e.InnerText } ;
      break ;
    case "Id" :
      int id ;
      int.TryParse(e.InnerText,out id) ;
      if ( item == null ) item = new AccessPoint() ;
      item.Id = id ;
      break ;
    case "Value" :
      bool value ;
      bool.TryParse(e.InnerText,out value) ;
      if ( item == null ) item = new AccessPoint() ;
      item.Value = value ;
      break ;
    }
  }
  if ( item != null ) yield return item ;
}

还有一点需要注意:您可能想让您的 AccessPoint 类实现 IComparable&lt;AccessPoint&gt;,这样您的字典就会表现得更像您所期望的那样:

class AccessPoint : IComparable<AccessPoint>
{
  public string Name { get ; set ; }
  public int  Id { get ; set ; }
  public bool Value { get ; set ; }

  public int CompareTo( AccessPoint other )
  {
    int cc = other != null ? 0 : -1 ;
    if ( cc == 0 )
    {
      cc = String.Compare( this.Name , other.Name , StringComparison.Ordinal ) ;
    }
    if ( cc == 0 )
    {
      cc = this.Id.CompareTo( other.Id ) ;
    }
    return cc ;
  }
  public override string ToString()
  {
    return string.Format( "name={0}, id={1}, value={2}" , Name,Id,Value ) ;
  }
}

【讨论】:

  • 感谢一百万个 Nicholas,它确实拓宽了我的思路,并且像魅力一样工作!非常感谢!
猜你喜欢
  • 1970-01-01
  • 2011-10-23
  • 2015-04-25
  • 2019-03-22
  • 2018-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-31
相关资源
最近更新 更多