Как сохранить и получить значения из Xml без приведения?

Что-то, что я действительно ненавижу, это приведение каждого элемента или значения атрибута из файла XML.

Этот момент я создаю в сотнях модулей методов, в которых указывается, как преобразовать объект в XmlFile. Поверьте, это очень устало. Так что я подумываю об альтернативе.

Я занимался расследованием XSD, я не уверен, будет ли это моим спасением. Я использую Linq для Xml, чтобы сохранить и получить значения. Я имею в виду, мои объекты составлены так:

- Foo1 : Foo
   - Range1 : Range
      - X : int
      - Y : int
- ...

Как видите, у них много узлов. Есть ли другая альтернатива для этого? Я имею в виду, сильно печатает.

4 ответа

Решение

Вы можете попробовать эти методы расширения XElement: http://searisen.com/xmllib/extensions.wiki

Вот пример силы этого, учитывая этот XML из другого поста:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <PatchCreation
    Id="224C316C-5894-4771-BABF-21A3AC1F75FF"
    CleanWorkingFolder="yes"
    OutputPath="patch.pcp"
    WholeFilesOnly="yes">
    <PatchInformation
        Description="Update Patch"
        Comments="Update Patch"
        ShortNames="no"
        Languages="1033"
        Compressed="yes"
        Manufacturer="me"/>

    <PatchMetadata
        AllowRemoval="yes"
        Description="Update Patch"
        ManufacturerName="me"
        TargetProductName="Update"
        MoreInfoURL="http://andrewherrick.com/"
        Classification="Update"
        DisplayName="Update Patch"/>

    <Family DiskId="5000"
        MediaSrcProp="Sample"
        Name="Update"
        SequenceStart="5000">
      <UpgradeImage SourceFile="c:\new.msi" Id="PatchUpgrade">
        <TargetImage SourceFile="c:\old.msi" Order="2" Id="PatchUpgrade" IgnoreMissingFiles="no" />
      </UpgradeImage>
    </Family>

    <PatchSequence PatchFamily="SamplePatchFamily"
        Sequence="1.0.0.0"
        Supersede="yes" />
  </PatchCreation>
</Wix>

Это устанавливает значение атрибута SourceFile тега UpgradeImage и тега TargetImage внутри UpgradeImage и его SourceFile.

XElement wix = XElement.Load(xmlFile1.FullName);
wix.Set("PatchCreation/Family/UpgradeImage/SourceFile", "upgrade path", true)
   .Set("TargetImage/SourceFile", "target path", true);

Вы также можете получить их значения таким же образом (без приведения).

string upgradeSource = wix.Get("PatchCreation/Family/UpgradeImage/SourceFile", string.Empty);
string targetSource = wix.Get("PatchCreation/Family/UpgradeImage/TargetImage/SourceFile", string.Empty);

Или это можно записать как:

XElement upgradeImage = wix.GetElement("PatchCreation/Family/UpgradeImage");
string upgradeSource = upgradeImage.Get("SourceFile", string.Empty);
string targetSource = upgradeImage.Get("TargetImage/SourceFile", string.Empty);

Чтобы получить список целых чисел:

<root>
 <path>
  <list>
    <value>1</value>
    <value>12</value>
    <value>13</value>
    <value>14</value>
    <value>15</value>
   </list>
  </path>
</root>

Используйте метод GetEnumerable():

List<int> list = root
    .GetEnumerable("path/list/value", xvalue => xvalue.Get(null, int.MinValue));
    .ToList();

Чтобы установить новый список целых:

var list2 = new int[] { 1, 3, 4, 5, 6, 7, 8, 9, 0 };
root.SetEnumerable("path/list", list2, a => new XElement("value", a));

Что приводит к этому новому XML:

<root>
  <path>
    <list>
      <value>1</value>
      <value>3</value>
      <value>4</value>
      <value>5</value>
      <value>6</value>
      <value>7</value>
      <value>8</value>
      <value>9</value>
      <value>0</value>
    </list>
  </path>
</root>

Лучше всего использовать XmlSerialization. Так что сериализуйте в XML, а затем десериализуйте в объекты, тогда вам не нужно использовать приведение.

Иногда XML создается другим способом, отличным от сериализации. Тем не менее, вы все равно можете создавать классы, которые представляют вашу XML-структуру и десериализацию.

Например:

Public Class Foo
{
   public Range Range {get; set;}
}


public class Range
{
    public int X {get; set;}
    public int Y {get; set;}
}

Тогда вы используете это:

XmlSerializer ser = new XmlSerializer(typeof(Foo));

Я часто использую XSD для проверки структуры XML, частично именно по этой причине, и поскольку у меня нет конструкторов по умолчанию и / или нет личных полей, XMLSerialization тоже не часто вариант.

Если XML проверяется без ошибок, тогда я использую Linq2Xml и использую различные Parse(String s) методы для получения данных того типа, который требуется моему классу, но я пока не нашел чистого решения, которое бы делало это без какого-либо преобразования.

Этапы проверки позволяют избежать исключений из-за неправильного типа данных.

var query = from tst in xml.Elements("test")
            select new 
            {
                int1 = Int32.Parse(tst.Element("int1").Value), 
                double1 = Double.Parse(tst.Element("double1").Value), 
                double2 = Double.Parse(tst.Element("double2").Value), 
            }

РЕДАКТИРОВАТЬ: Добавлена ​​информация, чтобы ответить на комментарий "

Вы можете создать XSD непосредственно из графического интерфейса Visual Studio, и есть другие инструменты, которые делают это тоже, но я обычно просто использую Visual Studio. Откройте XML в редакторе, затем в меню XML выберите "Создать схему" (путь показан на снимке).

XML в XSD в Visual Studio IDE

Полученный XSD является очень простым. Он попытался пройти и "угадать" соответствующий тип данных для каждого узла, и он не содержит каких-либо дополнительных ограничений, но он делает достойную работу по созданию инфраструктуры для вас.

Как только это будет сделано, вы можете пойти и настроить типы данных, чтобы они лучше соответствовали вашим потребностям (при желании), и вы можете добавить свои собственные ограничения к данным (например, требовать, чтобы xs:int значение находится в диапазоне от 0 до 50 или xs:string значение должно быть длиной менее 10 символов - существуют десятки других возможностей, но это должно дать вам представление).

На самом деле я просто играл с языком XSD, и чем больше я это делал, тем он становился все легче. Сайт W3Schools был неоценим.

Мы используем Linq To Xsd для создания строго оберток классов типов вокруг XDocument,

Вы просто пишете файл схемы (Xsd) и включаете его в свой проект (как только вы взломали LinqToXsd в файл csproj:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="Foo1">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Range1">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="X" type="xs:int"/>
                            <xs:element name="Y" type="xs:int"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

Затем вы можете получить доступ к классам с тем же именем:

Foo1 foo = new Foo1()
{
    Range1 = new Foo1.Range1()
    {
        X = 7,
        Y = 10,
    }
};

foo.Save(foo.xml);

var input = Foo1.Load(input.xml);

Console.WriteLine(input.Range1.X.ToString());

J.

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