1

私が本当に嫌いなのは、Xmlファイルから各要素または属性値をキャストすることです。

この瞬間、私は何百ものモジュールで、オブジェクトをXmlFileに変換する方法を指定するメソッドを作成しています。信じて、これはとても疲れています。だから私は別の方法で考えています。

私はXSDについて調査していましたが、これが私の救いになるかどうかはわかりません。値を保存して取得するためにLinqtoXmlを使用しています。つまり、私のオブジェクトは次のように構成されています。

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

ご覧のとおり、多くのノードがあります。これを行う別の方法はありますか?つまり、強くタイプします。

4

4 に答える 4

1

次の 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>

これにより、UpgradeImage タグの SourceFile 属性の値と、UpgradeImage とその SourceFile 内の TargetImage タグが設定されます。

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();

int の新しいリストを設定するには:

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>
于 2012-04-04T17:35:54.300 に答える
0

あなたの最善の策は、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));
于 2012-04-04T16:13:03.387 に答える
0

私は XSD を使用して XML 構造を検証することがよくありますが、その理由の 1 つはこれとまったく同じです。また、デフォルトのコンストラクターやプライベート フィールドを持っていないため、XSDXMLSerializationもしばしばオプションではありません。

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 GUI から直接作成できます。それを行うツールは他にもありますが、私は通常、Visual Studio のみを使用します。エディターで XML を開き、XML メニューから [スキーマの作成] を選択します (パスはスナップショットに表示されます)。

Visual Studio IDE での XML から XSD への変換

結果の XSD は非常に基本的なものです。各ノードの適切なデータ型を調べて「推測」しようとしましたが、追加の制限は含まれていませんが、フレームワークをまとめる適切な仕事をしています。

それが完了したら、必要に応じてデータ型を微調整し (必要に応じて)、データに独自の制限を追加できます (xs:int値が 0 から 50 の範囲内にあることを要求するなど)。xs:string値の長さは 10 文字未満にする必要があります。他にも多くの可能性がありますが、それを参考にしてください)。

私は実際に XSD 言語をいじってみましたが、やればやるほど使いやすくなります。W3Schoolsサイトは非常に貴重でした。

于 2012-04-04T16:37:34.947 に答える
0

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.

于 2012-08-02T09:01:19.360 に答える