我有以下XML文件
<?xml version="1.0" ?>
<Persons>
<Person>
<Id>1</Id>
<Name>temp</Name>
<Qlid>1234</Qlid>
<Manager>3</Manager>
</Person>
<Person>
<Id>2</Id>
<Name>someone</Name>
<Qlid>5678</Qlid>
<Manager>1</Manager>
</Person>
</Persons>
我正在尝试使用以下c#函数
来阅读它protected void readXmlFile()
{
FileStream fs = new FileStream("C:/Documents and Settings/me/Desktop/chart.xml",FileMode.Open);
XmlTextReader r = new XmlTextReader(fs);
//debug
StringWriter st = new StringWriter();
List<Person> persons = new List<Person>();
//Loop through persons in XML
while (r.Read())
{
if (r.NodeType == XmlNodeType.Element && r.Name == "Person")
{
Person newPerson = new Person();
while (r.NodeType != XmlNodeType.EndElement)
{
r.Read();
if (r.Name == "Id")
{
st.Write("67");
while (r.NodeType != XmlNodeType.EndElement)
{
r.Read();
if (r.NodeType == XmlNodeType.Text)
{
newPerson.Id = Int32.Parse(r.Value);
st.Write(r.Value);
}
}
}
r.Read();
if (r.Name == "Name")
{
while (r.NodeType != XmlNodeType.EndElement)
{
r.Read();
if (r.NodeType == XmlNodeType.Text)
{
newPerson.Name = (r.Value);
st.Write("23");
}
}
}
r.Read();
if (r.Name == "Qlid")
{
while (r.NodeType != XmlNodeType.EndElement)
{
r.Read();
if (r.NodeType == XmlNodeType.Text)
{
newPerson.Qlid = (r.Value);
st.Write(r.Value);
}
}
}
r.Read();
if (r.Name == "Manager")
{
while (r.NodeType != XmlNodeType.EndElement)
{
r.Read();
if (r.NodeType == XmlNodeType.Text)
{
newPerson.Manager = Int32.Parse(r.Value);
st.Write(r.Value);
}
}
}
//add to list
persons.Add(newPerson);
st.Write(90);
}
}
}
fs.Close();
if(r.Name =“Id”)和类似的ifs由于某种原因永远不会变为真,返回空人类
答案 0 :(得分:10)
除非你的XML非常庞大,并且无法一次性加载到内存中,否则我几乎肯定不会走这条路。
在XmlReader
或Linq2Xml上使用XmlDocument
的问题是,您缺少XPath或Linq的所有功能,这些功能旨在完全按照您的尝试进行操作这里:从xml中选择特定节点。
或者,看起来您只是将一些xml反序列化为dto,即Person
。这正是内置的xml序列化为您所做的。如果你愿意的话,你可以通过dto上的一些属性实现这一点。
但是,关于为什么这个具体不起作用:
检查Person
元素,然后在寻找不是结束元素的内容时循环。我的猜测是你希望下一个节点是Name
元素。事实并非如此。您的下一个Read()
会为您提供一个空白节点。这会抛弃您对所期望元素的所有后续测试。这突出了您正在做的事情的关键问题:这种方法极其脆弱到xml中的细微变化。每次你盲目地执行Read()时,你都假设你知道下一个节点是什么。如果它不是您所期望的,那么您的代码可能会失败,以至于在它实际发生故障之前不易发现。
是否有令人信服的理由不使用其他方法?我的直觉是,如果你这样做,你会省去很多麻烦!
答案 1 :(得分:3)
我将重申其他人的建议:使用LINQ to XML。它会更容易
。但是,关于您当前代码失败的原因:
r.Read();
if (r.Name == "Id") { ... }
r.Read();
if (r.Name == "Name") { ... }
// etc
这假定它将按照预期的顺序读取节点(不仅仅是元素 - 不要忘记文本节点等)。你应该只是阅读节点,直到你到达当前元素的末尾,并适当地对每个节点作出反应。
但是,这里是一个LINQ to XML的示例,仅用于比较:
XDocument doc = XDocument.Load("foo.xml")
List<Person> persons = doc.Elements("Person")
.Select(x => new Person
{
Id = (int) x.Element("Id"),
Name = (string) x.Element("Person"),
Manager = (string) x.Element("Manager")
// etc
});
.ToList();
不可否认,这当前假设 是一个Id
元素,但有一些方法可以使它变得更复杂。如您所见,它比使用XmlReader
要简单得多。
答案 2 :(得分:1)
您的代码假定XML文件始终采用与以下顺序的数据相同的格式:
你不能做出这个假设。
如果您需要使用此方法,则需要重新构建代码以循环,直到达到<\Person>
。然后在循环中切换r.Name
以设置newPerson
的相应属性。
答案 3 :(得分:0)
正如@Rob所说,你的代码正在返回丢失测试的空格。您可以在WhiteSpaceHandling
上指定XmlTextReader
,这将解决您当前的问题。
r.WhitespaceHandling = WhitespaceHandling.None;
答案 4 :(得分:0)
可能需要使用XmlReader,可能是因为内存限制。在这种情况下,使用XmlReader.ReadSubTree()
方法可能是有益的,这样就无需检查EndElement节点类型。此外,由于SubTree的大小较小,因此它们也可以转换为具有较小内存消耗的XmlDocuments。