Как обработать файл XML, имеющий иерархическую структуру, чтобы получить внутренние детали - PullRequest
0 голосов
/ 31 января 2019

У меня большой XML-файл со следующей структурой. Это фрагмент, который содержит множество <xn:TestElement> узлов.

    <?xml version="1.0" encoding="utf-8" ?>
            <testDataFile
           xmlns="http://www.3gpp.org/ftp/specs/archive/32_series/32.615#configData"
           xmlns:xn="http://www.3gpp.org/ftp/specs/archive/32_series/32.625#genericNrm" xmlns:in="http://www.3gpp.org/ftp/specs/archive/32_series/32.695#inventoryNrm">
          <fileHeader fileFormatVersion="32.615 V6.3" vendorName="TestVendor"/>
            <configData dnPrefix="">
    <xn:SubNetwork id="ONRM_ROOT_MO">
      <xn:SubNetwork id="RNC425">
        <xn:TestElement id="DA_Test_place0">
          <xn:attributes>
            <xn:userLabel>DA_Test_place0</xn:userLabel>
          </xn:attributes>
          <in:InventoryUnit id="n/a">
            <in:attributes>
              <in:manufacturerData>ProductName=Non-subrack HW,SlotCount=0</in:manufacturerData>
            </in:attributes>
            <in:InventoryUnit id="0">
              <in:attributes>
                <in:vendorUnitTypeNumber>KRC11876/1_R4A</in:vendorUnitTypeNumber>
                <in:manufacturerData>ProductName=RUS 02 B8</in:manufacturerData>
              </in:attributes>
            </in:InventoryUnit>
            <in:InventoryUnit id="0">
              <in:attributes>
                <in:vendorUnitTypeNumber>test/1_R4A</in:vendorUnitTypeNumber>
              </in:attributes>
            </in:InventoryUnit>
          </in:InventoryUnit>
          <in:InventoryUnit id="n/a">
            <in:attributes>
              <in:manufacturerData>ProductName=Virtual subrack,SlotCount=2</in:manufacturerData>
            </in:attributes>
            <in:InventoryUnit id="1">
              <in:attributes>
                <in:vendorUnitTypeNumber>KDU127174/4_R2D/A</in:vendorUnitTypeNumber>
              </in:attributes>
            </in:InventoryUnit>
            <in:InventoryUnit id="1">
              <in:attributes>
                <in:vendorUnitTypeNumber>KDU127174/4_R2D/B</in:vendorUnitTypeNumber>
                <in:manufacturerData>ProductName=RUS 02 B7</in:manufacturerData>
              </in:attributes>
            </in:InventoryUnit>
          </in:InventoryUnit>
        </xn:TestElement>
        <xn:TestElement id="DA_Test_place1">

        </xn:TestElement>
      </xn:SubNetwork>
    </xn:SubNetwork>
  </configData>
            </testDataFile>

Теперь я хочу обработать этот XML-файл, например:

testelementname     slotdata                                inventory unit number
------------------------------------------------------------------------------
DA_Test_place0      ProductName=Non-subrack HW,SlotCount=0  KRC11876/1_R4A
DA_Test_place0      ProductName=Non-subrack HW,SlotCount=0  test/1_R4A
DA_Test_place0      ProductName=Virtual subrack,SlotCount=2  KDU127174/4_R2D/A
DA_Test_place0      ProductName=Virtual subrack,SlotCount=2  KDU127174/4_R2D/B

Как мне обработать этот xml-файл и получить информацию либо в datatable, либо в C # классах.Я написал следующий код, но он застрял с иерархией xml

while (reader.Read())
{
    if (reader.Name != "xn:TestElement")
    {
        reader.ReadToFollowing("xn:TestElement");
    }

    while (reader.NodeType == XmlNodeType.Element && reader.LocalName == "TestElement")
    {
        XElement elements = (XElement)XElement.ReadFrom(reader);
        testelemenname = reader.GetAttribute("id");
        slotdata = GetInventoryValue(elements, "manufacturerData");
        invenotry unit number = GetInventoryValue(elements, "vendorUnitTypeNumber");
    }
}

private static string GetInventoryValue(XElement pin, string input)
{
    XElement manufacturerData = pin.Descendants().Where(a => a.Name.LocalName == input).FirstOrDefault();

    if (manufacturerData != null)
    {
        return (string)manufacturerData;
    }
}

EDIT

Heirarchy of XML немного изменился и добавил два уровня 'SubNetwork 'узел и еще один узел' configData'and Пространства имен также изменились, теперь я не получаю результат

1 Ответ

0 голосов
/ 31 января 2019

Вы можете достичь желаемого результата, используя XDocument.

Здесь я создал образец консольного приложения для демонстрационных целей,

class Program
{
    public static void Main(string[] args)
    {
        XDocument doc = XDocument.Load(@"Path to your xml file");
        XNamespace ns = doc.Root.GetDefaultNamespace();
        XNamespace xdt = "http://www.3gpp.org";

        var result = doc.Descendants(ns + "TestElement")
        .Elements(ns + "InventoryUnit")
        .Elements(ns + "InventoryUnit")
        .Select(x => new
        {
            test_element_name = x.AncestorsAndSelf(ns + "TestElement").FirstOrDefault()?.Attribute("id")?.Value,
            slot_data = x.Ancestors(ns + "InventoryUnit").AncestorsAndSelf(ns + "InventoryUnit").FirstOrDefault().Element(ns + "attributes").Element(ns + "manufacturerData")?.Value,
            invenotry_unit_number = x.Element(ns + "attributes").Element(ns + "vendorUnitTypeNumber")?.Value,
        }).ToList();

        //-----------Print result--------------

        foreach (var item in result)
        {
            Console.WriteLine(item.test_element_name);
            Console.WriteLine(item.slot_data);
            Console.WriteLine(item.invenotry_unit_number);
            Console.WriteLine();
        }

        Console.ReadLine();
    }
}

Вывод:

enter image description here

Редактировать:

Если размер вашего файла XML слишком велик и XDocument не удалось его проанализировать, товы можете попробовать XmlSerializer как

XmlSerializer serializer = new XmlSerializer(new TestDataFile().GetType());
using (StringReader stringReader = new StringReader(File.ReadAllText(@"Path to your xml file")))
{
    TestDataFile testDataFile = (TestDataFile)serializer.Deserialize(stringReader);

     var result = testDataFile.ConfigData.SubNetwork.InnerSubNetwork.SelectMany(a => a.TestElement.SelectMany(x => x.InventoryUnit.SelectMany(y => y.IU
             .Select(z => new { test_element_name = x.Id, slot_data = y.Attributes.ManufacturerData, invenotry_unit_number = z.Attributes.VendorUnitTypeNumber })))).ToList();

    foreach (var item in result)
    {
        Console.WriteLine(item.test_element_name);
        Console.WriteLine(item.slot_data);
        Console.WriteLine(item.invenotry_unit_number);
        Console.WriteLine();
    }
}

И вам нужна иерархия классов ниже для десериализации вашего xml,

[XmlRoot(ElementName = "fileHeader", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.695#inventoryNrm")]
public class FileHeader
{
    [XmlAttribute(AttributeName = "fileFormatVersion")]
    public string FileFormatVersion { get; set; }
    [XmlAttribute(AttributeName = "vendorName")]
    public string VendorName { get; set; }
}

[XmlRoot(ElementName = "attributes", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.695#inventoryNrm")]
public class Attributes
{
    [XmlElement(ElementName = "userLabel", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.695#inventoryNrm")]
    public string UserLabel { get; set; }
    [XmlElement(ElementName = "manufacturerData", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.695#inventoryNrm")]
    public string ManufacturerData { get; set; }
    [XmlElement(ElementName = "vendorUnitTypeNumber", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.695#inventoryNrm")]
    public string VendorUnitTypeNumber { get; set; }
}

[XmlRoot(ElementName = "InventoryUnit", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.695#inventoryNrm")]
public class InnerInventoryUnit
{
    [XmlElement(ElementName = "attributes", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.695#inventoryNrm")]
    public Attributes Attributes { get; set; }
    [XmlAttribute(AttributeName = "id")]
    public string Id { get; set; }
}


[XmlRoot(ElementName = "InventoryUnit", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.695#inventoryNrm")]
public class InventoryUnit
{
    [XmlElement(ElementName = "attributes", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.695#inventoryNrm")]
    public Attributes Attributes { get; set; }
    [XmlAttribute(AttributeName = "id")]
    public string Id { get; set; }
    [XmlElement(ElementName = "InventoryUnit", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.695#inventoryNrm")]
    public List<InnerInventoryUnit> IU { get; set; }
}

[XmlRoot(ElementName = "TestElement", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.625#genericNrm")]
public class TestElement
{
    [XmlElement(ElementName = "InventoryUnit", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.695#inventoryNrm")]
    public List<InventoryUnit> InventoryUnit { get; set; }
    [XmlAttribute(AttributeName = "id")]
    public string Id { get; set; }
}

[XmlRoot(ElementName = "SubNetwork", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.625#genericNrm")]
public class InnerSubNetwork
{
    [XmlElement(ElementName = "TestElement", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.625#genericNrm")]
    public List<TestElement> TestElement { get; set; }
    [XmlAttribute(AttributeName = "id")]
    public string Id { get; set; }
}

[XmlRoot(ElementName = "SubNetwork", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.625#genericNrm")]
public class SubNetwork
{
    [XmlElement(ElementName = "SubNetwork", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.625#genericNrm")]
    public List<InnerSubNetwork> InnerSubNetwork { get; set; }
    [XmlAttribute(AttributeName = "id")]
    public string Id { get; set; }
}

[XmlRoot(ElementName = "configData", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.615#configData")]
public class ConfigData
{
    [XmlElement(ElementName = "SubNetwork", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.625#genericNrm")]
    public SubNetwork SubNetwork { get; set; }
    [XmlAttribute(AttributeName = "dnPrefix")]
    public string DnPrefix { get; set; }
}

[XmlRoot(ElementName = "testDataFile", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.615#configData")]
public class TestDataFile
{
    [XmlElement(ElementName = "fileHeader", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.615#configData")]
    public FileHeader FileHeader { get; set; }
    [XmlElement(ElementName = "configData", Namespace = "http://www.3gpp.org/ftp/specs/archive/32_series/32.615#configData")]
    public ConfigData ConfigData { get; set; }
    [XmlAttribute(AttributeName = "xmlns")]
    public string Xmlns { get; set; }
    [XmlAttribute(AttributeName = "xn", Namespace = "http://www.w3.org/2000/xmlns/")]
    public string Xn { get; set; }
    [XmlAttribute(AttributeName = "in", Namespace = "http://www.w3.org/2000/xmlns/")]
    public string In { get; set; }
}
...