【问题标题】:How to pass trough all nodes and put the element values in a class separately如何通过所有节点并将元素值分别放在一个类中
【发布时间】:2020-06-24 22:49:21
【问题描述】:

所以,我是 XML 的新手,我正在尝试创建一些将从 xml 文件中提取的代码列表。

'ParentId' == -1 的每个节点都有一些相关的节点。每个节点都有四个具有不同值的单元格,我需要将它们放入“Campo”类中。这样,每个字段都会生成一个列表,我用它来填充一些控件。

我正在尝试使用 Linq 解决这个问题,到目前为止,我已经弄清楚了如何获得继任者和前任者字段。问题是我无法在“Campo”类的对应参数上分别获取四个单元格。该代码仅返回所有 Class 参数的第一个元素(“Cell”)。

我做错了什么?谢谢。

这是 xml 结构:

<TreeList>
<Nodes>
<Node ParentId="-1" Id="0">
<NodeData>
<Cell xsi:type="xsd:string">OBRA</Cell>
<Cell xsi:type="xsd:string">Obra/Cliente</Cell>
<Cell xsi:type="xsd:string">Lista de Itens</Cell>
<Cell xsi:type="xsd:string">4</Cell>
</NodeData>
</Node>
<Node ParentId="0" Id="1">
<NodeData>
<Cell xsi:type="xsd:string">PMG</Cell>
<Cell xsi:type="xsd:string">Presa Monte Grande</Cell>
<Cell xsi:type="xsd:string">Código Fixo</Cell>
<Cell xsi:type="xsd:string">4</Cell>
</NodeData>
</Node>
</Nodes>
</Treelist>

这是我目前所做的:

 string caminho = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
        string caminhoCompleto = caminho + @"\OBRA.xml";
        XDocument xml = XDocument.Load(caminhoCompleto);
        List<Campo> codigos = (from codigo in xml.Root.Elements("Nodes").Elements("Node")
                              from node in codigo.Descendants("NodeData")
                              where (int)codigo.Attribute("ParentId") == -1
                              select new Campo
                              {
                                  Codigo = (string)node.Element("Cell").Value,
                                  Descricao = (string)node.Element("Cell").Value,
                                  TipoCampo = (int)node.Element("Cell").Value, //This line return error
                                  NumCarac = (int)node.Element("Cell").Value,
                              }
                        ).ToList();
        foreach (Campo cp in codigos)
        {
            Console.WriteLine("Field: {0}", cp.Codigo);
            Console.WriteLine("Field: {0}", cp.Descricao);
            Console.WriteLine("Field: {0}", cp.TipoCampo);
            Console.WriteLine("Field: {0}", cp.NumCarac);
        }
        Console.ReadLine();                               
    }
}

class Campo
{
    public string Codigo { get; set; }
    public string Descricao { get; set; }
    public int TipoCampo { get; set; }
    public int NumCarac { get; set; }
    public List<Campo> Itens;

}

这是我目前得到的结果

Field: OBRA
Field: OBRA
Field: OBRA
Field: OBRA

我正在寻找的结果

Field: OBRA
Field: Obra/Cliente
Field: 3
Field: 4

【问题讨论】:

    标签: c# xml linq linq-to-xml


    【解决方案1】:

    如果您遇到的唯一问题是数据类型转换,那么您似乎走在了正确的轨道上 - 这是一种解决方法:值是字符串,因此您可以只使用 int.Parse 或 @987654322 @

    UPD 所以您似乎希望&lt;NodeData&gt; 的所有后代为您形成一个Campo 对象。您可以编写另一个扩展方法并在查询中使用它来简化创建Campo 对象的方式。请参阅下面的更新代码:

    public static class Extensions
    {
        public static int TryParseInt(this string value)
        {
            int v = default(int);
            if (int.TryParse(value, out v))
            {
                return v;
            }
            throw new ArgumentException("optionally do something on failure");
        }
    
        public static Campo ParseCells(this XElement node)
        {
            // here I'm able to query for all descendants directly because your source data seems to only have one NodeData for each Node. You could change XPath to suit your actual case
            var cells = node.XPathSelectElements("NodeData/Cell").ToArray();
            return new Campo
            {
                Codigo = (string)cells[0].Value,
                Descricao = (string)cells[1].Value,
                TipoCampo = int.Parse(cells[2].Value), //either do int.Parse
                NumCarac = cells[3].Value.TryParseInt(), // or opt for int.TryParse through a convenience extension method
            };
        }
    }
    void Main()
    {
        string caminho = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
        //string caminhoCompleto = caminho + @"\OBRA.xml";
        XDocument xml = XDocument.Parse("<TreeList><Nodes><Node ParentId=\"-1\" Id=\"0\"><NodeData><Cell >OBRA</Cell><Cell >Obra/Cliente</Cell><Cell >Lista de Itens</Cell><Cell >4</Cell></NodeData></Node><Node ParentId=\"0\" Id=\"1\"><NodeData><Cell >PMG</Cell><Cell >Presa Monte Grande</Cell><Cell >Código Fixo</Cell><Cell >4</Cell></NodeData></Node></Nodes></TreeList>");
        var codigos = (from codigo in xml.Root.Elements("Nodes").Elements("Node")                                                  
                               where (int)codigo.Attribute("ParentId") == -1                           
                               select codigo.ParseCells() // not that ParseCells takes care of object creation for us - we can simplify the LINQ and remove extra nesting here
                        ).ToList();
        foreach (Campo cp in codigos)
        {
            Console.WriteLine("Field: {0}", cp.Codigo);
            Console.WriteLine("Field: {0}", cp.Descricao);
            Console.WriteLine("Field: {0}", cp.TipoCampo);
            Console.WriteLine("Field: {0}", cp.NumCarac);
        }
        Console.ReadLine();
    }
    
    
    public class Campo
    {
        public string Codigo { get; set; }
        public string Descricao { get; set; }
        public int TipoCampo { get; set; }
        public int NumCarac { get; set; }
        public List<Campo> Itens;
    }
    

    附注:我相信您的源字段和代码不同步,因为TipoCampo 应该是 int,但源数据中有一个字符串。

    【讨论】:

    • 感谢您的回复。事实上,我通过它的问题是因为,我正在寻找分别获取四个单元格,但代码只给了我第一个 XElement(“Cell”)。例如,它有时会看到这样的想法:Field 1: OBRA Field 2: Description Field 3: Type: Field 4: Characters Numbers 但我在这段代码中得到的结果是:``` 字段 1:OBRA 字段 2:OBRA 字段 3:OBRA 字段 4:OBRA ```
    • 刚刚更新了答案,认为您可能想要更多,然后只需键入强制 :)
    • 是的,肯定会看到更新 - 它对您所追求的有帮助吗?
    • 谢谢你,你明白我在经历什么。我会试试你的方法,稍后再回来说它是否有效。 :)
    • 你是我的英雄。它就像一个魅力。我可以遍历列表中的所有节点。所以现在我可以按顺序得到我想要的所有参数。谢谢大佬。
    猜你喜欢
    • 1970-01-01
    • 2013-02-04
    • 1970-01-01
    • 1970-01-01
    • 2018-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多