DescendantsUntil() в случае вложенных элементов

В моем предыдущем вопросе: ссылка,

Я научился использовать метод расширения DescendantsUntil() для поиска самых верхних элементов (Parent) и их самых верхних потомков (Children).

Предположим теперь, что у нас есть больше потомков (родитель, дети, племянники и т. д.):

<?xml version = "1.0" encoding = "utf-8"?>
<Document>
    <Interface>
        <Sections xmlns = "http://www.siemens.com/automation/Openness/SW/Interface/v4">
            <Section Name = "Static">
                <Member Name = "3bool1" Datatype = "&quot;3bool&quot;" Remanence = "NonRetain" Accessibility = "Public">
                    <AttributeList>
                        <BooleanAttribute Name = "ExternalAccessible" SystemDefined = "true">true</BooleanAttribute>
                        <BooleanAttribute Name = "ExternalVisible" SystemDefined = "true">true</BooleanAttribute>
                        <BooleanAttribute Name = "ExternalWritable" SystemDefined = "true">true</BooleanAttribute>
                        <BooleanAttribute Name = "SetPoint" SystemDefined = "true">false</BooleanAttribute>
                    </AttributeList>
                    <Sections>
                        <Section Name = "None">
                            <Member Name = "bool1" Datatype = "Bool" />
                            <Member Name = "bool2" Datatype = "Bool" />
                            <Member Name = "bool3" Datatype = "Bool" />
                            <Member Name = "3bool1" Datatype = "&quot;3bool&quot;" Remanence = "NonRetain" Accessibility = "Public">
                                <AttributeList>
                                    <BooleanAttribute Name = "ExternalAccessible" SystemDefined = "true">true</BooleanAttribute>
                                    <BooleanAttribute Name = "ExternalVisible" SystemDefined = "true">true</BooleanAttribute>
                                    <BooleanAttribute Name = "ExternalWritable" SystemDefined = "true">true</BooleanAttribute>
                                    <BooleanAttribute Name = "SetPoint" SystemDefined = "true">false</BooleanAttribute>
                                </AttributeList>
                                <Sections>
                                    <Section Name = "None">
                                        <Member Name = "bool1" Datatype = "Bool" />
                                        <Member Name = "bool2" Datatype = "Bool" />
                                        <Member Name = "bool3" Datatype = "Bool" />
                                    </Section>
                                </Sections>
                            </Member>
                        </Section>
                    </Sections>
                </Member>
                <Member Name = "int7" Datatype = "Int" Remanence = "NonRetain" Accessibility = "Public">
                    <AttributeList>
                        <BooleanAttribute Name = "ExternalAccessible" SystemDefined = "true">true</BooleanAttribute>
                        <BooleanAttribute Name = "ExternalVisible" SystemDefined = "true">true</BooleanAttribute>
                        <BooleanAttribute Name = "ExternalWritable" SystemDefined = "true">true</BooleanAttribute>
                        <BooleanAttribute Name = "SetPoint" SystemDefined = "true">true</BooleanAttribute>
                    </AttributeList>
                </Member>
            </Section>
        </Sections>
    </Interface>
 </Document>

Используя метод расширения DescendantsUntil(), я могу легко фильтровать родительские и дочерние элементы.

string path = ("C:\\Users\\");
XDocument doc = XDocument.Load(path + "File.xml");
XNamespace ns = "http://www.siemens.com/automation/Openness/SW/Interface/v4";
XName name = ns + "Member";

var memb = doc
    .Root.DescendantsUntil(e => e.Name == name)
    .Select(e => (Parent: e, Children: e.DescendantsUntil(c => c.Name == name).ToList()))
    //.Where(i => i.Children.Count > 0); // Uncomment to filter out <Member> elements with no child members.
    .ToList();
  

Теперь, как я могу использовать DescendantsUntil() для извлечения элементов Parent, Children, Nephews и вообще, как извлечь всех потомков, если есть еще один вложенный?

У вас есть древовидная структура, и вы должны использовать древовидные алгоритмы для разбора по частям. Вероятно, вам нужен рекурсивный алгоритм.

jdweng 13.04.2023 12:24
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Попробуйте такой код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication52
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);
            XElement xSections = doc.Descendants().Where(x => x.Name.LocalName == "Sections").FirstOrDefault();
            XNamespace ns = xSections.GetDefaultNamespace();
            Sections root = new Sections();
            root.ParseSections(xSections, ns);
        }
    }
    public class Sections
    {
        public List<Section> sections { get; set; }

        public void ParseSections(XElement xSections, XNamespace ns)
        {
            List<XElement> sections = xSections.Elements(ns + "Section").ToList();
            foreach (XElement section in sections)
            {
                if (this.sections == null) this.sections = new List<Section>();
                Section childSection = new Section();
                this.sections.Add(childSection);
                childSection.ParseSection(section, ns);
            }
        }
    }
    public class Section
    {
        public string name { get; set; }
        public List<Member> members { get; set; }

        public void ParseSection(XElement xSection, XNamespace ns)
        {
            this.name = (string)xSection.Attribute("Name");
            foreach (XElement xMember in xSection.Elements(ns + "Member"))
            {
                if (this.members == null) this.members = new List<Member>();
                Member member = new Member();
                this.members.Add(member);
                member.ParseMember(xMember, ns);

            }
        }
    }
    public class Member
    {
        public string name { get; set; }
        public string remanence { get; set; }
        public string accessibility { get; set; }
        public Dictionary<string, Boolean> attributes { get; set; }
        public Sections sections { get; set; }

        public void ParseMember(XElement member, XNamespace ns)
        {
            this.name = (string)member.Attribute("Name");
            this.remanence = (string)member.Attribute("Remanence");
            this.accessibility = (string)member.Attribute("Accessibility");
            XElement attributeList = member.Element(ns + "AttributeList");
            if (attributeList != null)
            {
                foreach (XElement attribute in attributeList.Descendants(ns + "BooleanAttribute"))
                {
                    if (attributes == null) attributes = new Dictionary<string, bool>();
                    string attributeName = (string)attribute.Attribute("Name");
                    Boolean attributeValue = (Boolean)attribute;
                    attributes.Add(attributeName, attributeValue);
                }
            }
            XElement xSections = member.Element(ns + "Sections");
            if (xSections != null)
            {
                Sections childSections = new Sections();
                this.sections = childSections;
                childSections.ParseSections(xSections, ns);
            }
            
        }
    }
}

Пожалуйста, всегда объясняйте код. Объясните будущим читателям, где найти основные части, отвечающие на вопрос.

Gert Arnold 13.04.2023 13:42

Я не могу понять, как использовать этот код, извините.

fabrizio scarpetta 13.04.2023 15:47

Код анализирует XML и создает дерево (класс), корнем которого является вершина дерева.

jdweng 13.04.2023 15:57
Ответ принят как подходящий

Я нашел решение сам (может быть, это может быть полезно для вас).

Если вы хотите использовать метод расширения «DescendantsUntil», чтобы найти больше вложенных уровней, вам просто нужно снова вызвать его внутри оператора foreach, как в следующем рабочем коде:

var memb_L0 = doc
    .Root.DescendantsUntil(e => e.Name == name)
    .Select(e => (Parent: e, Children: e.DescendantsUntil(c => c.Name == name).ToList()))
    //.Where(i => i.Children.Count > 0); // Uncomment to filter out <Member> elements with no child members.
    .ToList();


foreach (var ele in memb_L0)
{
    Console.WriteLine("Parent: \"{0}\", ", ele.Parent.Attribute("Name")?.Value);

    var memb_L1 = ele.Parent.DescendantsUntil(e => e.Name == name).Select(e => (Children: e, Nephew: e.DescendantsUntil(c => c.Name == name).ToList())).ToList();

    memb_L1.ForEach(i => Console.WriteLine("Children: \"{0}\", Nephews: {1}",                              
                               i.Children.Attribute("Name")?.Value,
                               i.Nephew.Count == 0
                               ? "None" :
                               string.Join(",",
                                           i.Nephew.Select(c => $"\"{c.Attribute("Name")?.Value}\""))));

}

Вот результат:

Parent: "3bool1",
Children: "bool1", Nephews: None
Children: "bool2", Nephews: None
Children: "bool3", Nephews: None
Children: "3bool1", Nephews: "bool1","bool2","bool3"
Parent: "int7"

Помните, что Stack Overflow предназначен не только для решения непосредственной проблемы, но и для того, чтобы помочь будущим читателям найти решения похожих проблем, что требует понимания базового кода. Это особенно важно для членов нашего сообщества, которые являются новичками и не знакомы с синтаксисом. Учитывая это, можете ли вы отредактировать свой ответ, включив в него объяснение того, что вы делаете, и почему вы считаете, что это лучший подход?

Jeremy Caney 18.04.2023 03:14

Другие вопросы по теме