我早些时候问了一个问题,我得到了使用XML避难所化的提示将我的XML内容解析为C#对象。经过一番谷歌搜索和乱七八糟的作用,我得到了一个工作的挑战,但是我有一个问题。
我的XML文件看起来像这样:(这只是文件的一部分)
<osm>
<n id="2638006578" l="5.9295547" b="52.5619519" />
<n id="2638006579" l="5.9301973" b="52.5619526" />
<n id="2638006581" l="5.9303625" b="52.5619565" />
<n id="2638006583" l="5.9389539" b="52.5619577" />
<n id="2638006589" l="5.9386643" b="52.5619733" />
<n id="2638006590" l="5.9296231" b="52.5619760" />
<n id="2638006595" l="5.9358987" b="52.5619864" />
<n id="2638006596" l="5.9335913" b="52.5619865" />
<w id="453071384">
<nd rf="2638006581" />
<nd rf="2638006590" />
<nd rf="2638006596" />
<nd rf="2638006583" />
<nd rf="2638006578" />
</w>
<w id="453071385">
<nd rf="2638006596" />
<nd rf="2638006578" />
<nd rf="2638006581" />
<nd rf="2638006583" />
</w>
</osm>
我设法将其列为对象,并且它的工作原理。问题如下:<w>
元素下的<nd>
元素具有参考ID,该参考ID与<n>
元素的ID相同。多个<w>
元素可能具有相同的<n>
元素参考,因此<n>
元素。
当前代码我有一个表示<nd>
元素的NodeReference对象,但是我想根据参考ID和Node ID将类别类直接链接到节点类。因此,基本上,类的方式应具有节点列表,而不是一个节点列表。我应该有一个分开的节点列表,以防止使用相同数据的新实例的方法(例如,如果两种方式参考相同的节点,则他们也应该指向相同的节点实例,而不是两个相同的节点实例,如果那样有意义..)
我基本上需要基于Noderference ID访问Node实例的LON/LAT/ID字段。
这是我的代码:
datacollection类
[XmlRoot("osm")]
public class DataCollection {
[XmlElement("n")]
public List<Node> Nodes { get; private set; }
[XmlElement("w")]
public List<Way> Ways { get; private set; }
public DataCollection() {
this.Nodes = new List<Node>();
this.Ways = new List<Way>();
}
}
节点类
[Serializable()]
public class Node {
[XmlAttribute("id", DataType = "long")]
public long ID { get; set; }
[XmlAttribute("w", DataType = "double")]
public double Lat { get; set; }
[XmlAttribute("l", DataType = "double")]
public double Lon { get; set; }
}
方法
[Serializable()]
public class Way {
[XmlAttribute("id", DataType = "long")]
public long ID { get; set; }
[XmlElement("nd")]
public List<NodeReference> References { get; private set; }
public Way() {
this.References = new List<NodeReference>();
}
}
nodeReference
[Serializable()]
public class NodeReference {
[XmlAttribute("rf", DataType = "long")]
public long ReferenceID { get; set; }
}
阅读XML文件
public static void Read() {
XmlSerializer serializer = new XmlSerializer(typeof(DataCollection));
using (FileStream fileStream = new FileStream(@"path/to/file.xml", FileMode.Open)) {
DataCollection result = (DataCollection)serializer.Deserialize(fileStream);
// Example Requested usage: result.Ways[0].Nodes
}
Console.Write("");
}
预先感谢!如果您有问题或答案,请告诉我!
我同意@AlexanderPetrov,最容易链接对象之后。我正在使用词典进行快速查找,并在NodeReferece
类中使用额外的Node
属性。
var NodeById = this.Nodes.ToDictionary(n => n.ID, n => n);
foreach (var way in this.Ways) {
foreach (var nd in way.References) {
nd.Node = NodeById[nd.ReferenceID];
}
}
通过查询属性导入System.Xml.Serialization
名称空间后,可以在LINQPAD中运行以下代码。
void Main()
{
XmlSerializer serializer = new XmlSerializer(typeof(DataCollection));
using (FileStream fileStream = new FileStream(@"file.xml", FileMode.Open)) {
DataCollection result = (DataCollection)serializer.Deserialize(fileStream);
result.Index();
result.Ways[0].References[0].Node.Lon.Dump();
// -> 5,9303625
}
}
// --------------------------------------------------------------------------
[XmlRoot("osm")]
public class DataCollection {
[XmlElement("n")]
public List<Node> Nodes = new List<Node>();
[XmlElement("w")]
public List<Way> Ways = new List<Way>();
public void Index() {
var NodeById = this.Nodes.ToDictionary(n => n.ID, n => n);
foreach (var way in this.Ways) {
foreach (var nd in way.References) {
nd.Node = NodeById[nd.ReferenceID];
}
}
}
}
// --------------------------------------------------------------------------
[Serializable()]
public class Node {
[XmlAttribute("id", DataType = "long")]
public long ID { get; set; }
[XmlAttribute("w", DataType = "double")]
public double Lat { get; set; }
[XmlAttribute("l", DataType = "double")]
public double Lon { get; set; }
}
// --------------------------------------------------------------------------
[Serializable()]
public class Way {
[XmlAttribute("id", DataType = "long")]
public long ID { get; set; }
[XmlElement("nd")]
public List<NodeReference> References = new List<NodeReference>();
}
// --------------------------------------------------------------------------
[Serializable()]
public class NodeReference {
[XmlAttribute("rf", DataType = "long")]
public long ReferenceID { get; set; }
[XmlIgnore]
public Node Node { get; set; }
}
我猜我不可能使用标准XmlSerializer
进行。
您可以通过实现IXmlSerializable
接口或使用自定义XmlReader
。
但是,最简单的方法是在避免后用以下代码手动填充所需的收集:
DataCollection result = (DataCollection)serializer.Deserialize(fileStream);
foreach (var way in result.Ways)
foreach (var nodeReference in way.References)
way.Nodes.Add(result.Nodes.First(node => node.ID == nodeReference.ReferenceID));
将Nodes
属性添加到Way
类:
public class Way
{
[XmlAttribute("id", DataType = "long")]
public long ID { get; set; }
[XmlElement("nd")]
public List<NodeReference> References { get; private set; }
public List<Node> Nodes { get; set; }
public Way()
{
this.References = new List<NodeReference>();
}
}