Как пройти через все узлы и поместить значения элемента в класс отдельно - PullRequest
0 голосов
/ 12 марта 2020

Итак, я новичок ie в XML, и я пытаюсь создать несколько списков кодов, которые будут извлечены из файла xml.

Каждый узел с 'ParentId '== -1 имеет несколько связанных с ним узлов. И у каждого узла есть четыре ячейки с разными значениями, которые мне нужно поместить в класс «Кампо». Таким образом, каждое поле генерирует список, который я использую для заполнения некоторых элементов управления.

Я пытаюсь решить это с помощью Linq, и до сих пор я выяснил, как получить поля-предшественники и предшественники. Проблема в том, что я не могу получить четыре ячейки отдельно, по соответствующему параметру класса "Кампо". Код возвращает только первый элемент («Ячейка») для всех параметров класса.

Что я делаю не так? Спасибо.

Это структура 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

1 Ответ

0 голосов
/ 13 марта 2020

Похоже, вы на правильном пути, если единственная проблема, с которой вы сталкиваетесь, связана с преобразованием типов данных - это один из способов решения этой проблемы: значения являются строками, поэтому вы можете либо просто int.Parse или int.TryParse

UPD , поэтому кажется, что вы хотите, чтобы все потомки <NodeData> образовали вас один 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;
}

Примечание: я считаю, что ваши исходные поля и код не синхронизированы c, так как TipoCampo должно быть int, но в исходных данных есть строка ,

...