从表示嵌套属性的字符串列表构造 XML

本文关键字:列表 XML 字符串 表示 嵌套 属性 | 更新日期: 2023-09-27 18:30:40

>我正在尝试构造一个XML,表示对象,但仅使用在2个对象之间修改的属性和第二个对象中的值。我不知道类的结构,但我知道我将始终拥有同一类的 2 个对象。

例:

public class A
{
    public B Property_A_B { get; set; }
    public C Property_A_C { get; set; }
}
public class B
{
    public int Property_B_Int { get; set; }
    public string Property_B_String { get; set; }
}
public class C
{
    public bool Property_C_Bool { get; set; }
    public D Property_C_D { get; set; }
}
public class D
{
    public double Property_D_Double { get; set; }
}

我有 2 个 A 类型的对象。如果我的 2 个对象之间的属性 Property_B_IntProperty_B_StringProperty_D_Double 不同,我有一个字符串列表,其中包含:

"A.Property_A_B.Property_B_Int"
"A.Property_A_B.Property_B_String"
"A.Property_A_C.Property_C_D.Property_D_Double"

使用这 3 个字符串,我必须构造该 XML:

<A>
    <Property_A_B>
        <Property_B_Int>12345</Property_B_Int>
        <Property_B_String>Hello world</Property_B_String>
    </Property_A_B>
    <Property_A_C>
        <Property_C_D>
            <Property_D_Double>456.76</Property_D_Double>
        </Property_C_D>
    </Property_A_C>
</A>

这些对象可以有许多不同的结构和结构。我只知道它们的类型和不同的属性名称 该函数必须适用于任何对象。

我写了那段代码:

XmlDocument xml = new XmlDocument();
using (MemoryStream ms = new MemoryStream()) {
    using (XmlWriter writer = XmlWriter.Create(ms)) {
        // Début du fichier
        writer.WriteStartDocument();
        // Début de l'objet
        writer.WriteStartElement(Objet_Fin.GetType().Name);
        // Ecriture des champs modifiés
        foreach (Difference diff in Differences) {
            string[] composants_diff = diff.PropertyName.Split({ "." }, StringSplitOptions.RemoveEmptyEntries);
            object sous_objet = Objet_Fin;
            Type type_sous_objet = null;
            PropertyInfo sous_propriete = default(PropertyInfo);
            foreach (string composant_diff in composants_diff) {
                // Pour chaque itération, on navigue vers la propriété suivante
                type_sous_objet = sous_objet.GetType();
                sous_propriete = type_sous_objet.GetProperty(composant_diff);
                sous_objet = sous_propriete.GetValue(sous_objet);
                // On ouvre un noeud XML pour chaque propriété passée
                writer.WriteStartElement(composant_diff);
            }
            writer.WriteValue(sous_objet.ToString());
            foreach (string composant_diff in composants_diff) {
                // On ferme chaque noeud ouvert
                writer.WriteEndElement();
            }
        }
        // Fin de l'objet
        writer.WriteEndElement();
        // Fin du fichier
        writer.WriteEndDocument();
        // Ecriture dans le flux
        writer.Flush();
    }
    // Ecriture du contenu du flux dans le XmlDocument
    ms.Position = 0;
    xml.Load(ms);
}

它几乎可以工作,但它会多次生成相同的对象属性,而不是一次。像这样:

<A>
    <Property_A_B>
        <Property_B_Int>12345</Property_B_Int>
    </Property_A_B>
    <Property_A_B>
        <Property_B_String>Hello world</Property_B_String>
    </Property_A_B>
    <Property_A_C>
        <Property_C_D>
            <Property_D_Double>456.76</Property_D_Double>
        </Property_C_D>
    </Property_A_C>
</A>

我不知道如何正确生成XML,每个对象属性只写一次。你能帮帮我吗?谢谢。

从表示嵌套属性的字符串列表构造 XML

唯一正确的方法是使用递归。 我使用StringReader()进行测试,它可以很容易地修改为StreamReader()。 我添加了一些真正严格的测试数据来验证代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string input1 = "a";
            List<XElement> results1 = ProcessData(input1);
            string input2 =
                "A.Property_A_B.Property_B_Int'n" +
                "A.Property_A_B.Property_B_String'n" +
                "A.Property_A_C.Property_C_D.Property_D_Double";
            List<XElement> results2 = ProcessData(input2);
            string input3 =
                "a.a.a.a.a.a.a'n" +
                "a.a.a.a.a.a.b'n" +
                "a.a.a.b";
            List<XElement> results3 = ProcessData(input3);
        }
        static List<XElement> ProcessData(string input)
        {
            StringReader reader = new StringReader(input);
            string inputLine = "";
            List<List<string>> properties = new List<List<string>>();
            while ((inputLine = reader.ReadLine()) != null)
            {
                properties.Add(inputLine.Split(new char[] { '.' }).ToList());
            }
            List<XElement> results = Recursive(properties);
            return results;
        }
        static List<XElement> Recursive(List<List<string>> input)
        {
            List<XElement> results = new List<XElement>();
            string parent = input[0][0];
            Dictionary<string, List<List<string>>> dict = input.GroupBy(m => m.FirstOrDefault(), n => n)
                .ToDictionary(m => m.Key, n => n.Select(p => p.Skip(1).ToList<string>()).ToList());
            foreach (string key in dict.Keys)
            {
                List<List<string>> subChilds = dict[key];
                //List<XElement> subElements = new List<XElement>();
                for (int i = subChilds.Count() - 1; i >= 0;  i--)
                {
                    if (subChilds[i].Count() == 0)
                    {
                        subChilds.RemoveAt(i);
                    }
                }
                List<XElement> child = null;
                if (subChilds.Count() > 0)
                {
                    child = Recursive(subChilds);
                    //elements.Add(child);
                }
                results.Add(new XElement(key, child));
            }
            return results;
        }
    }
}

又工作了一天,我终于找到了:

XmlDocument xml = new XmlDocument();
XmlElement rootNode = xml.CreateElement(Objet_Fin.GetType().Name);
xml.AppendChild(rootNode);
// Pour chaque différence
foreach (Difference diff in Differences) {
    string[] composants_diff = diff.PropertyName.Split({ "." }, StringSplitOptions.RemoveEmptyEntries);
    XmlElement parentNode = rootNode;
    XmlElement currentNode = null;
    string currentXPath = "/" + rootNode.Name;
    // Pour chaque propriété imbriquée
    for (i = 0; i <= composants_diff.Length - 2; i++) {
        // Construction du Xpath 
        currentXPath += "/" + composants_diff(i);
        // Selection du node à tester
        currentNode = rootNode.SelectSingleNode(currentXPath);
        if (currentNode == null) {
            // Si le node n'existe pas, on le créé et l'ajoute au parent
            currentNode = xml.CreateElement(composants_diff(i));
            parentNode.AppendChild(currentNode);
        }
        parentNode = currentNode;
    }
    // On écrit la propriété "finale"
    XmlNode newNode = xml.CreateElement(composants_diff.Last());
    newNode.InnerText = diff.Object2Value;
    parentNode.AppendChild(newNode);
}
return xml;

希望有一天有人会读到...