0

Xmlは以下の通りです。

<System>
  <ID></ID>
  <Name></Name>
  <Monitor>
    <ID></ID>
    <Type></Type>
    <Alert>
      <ID></ID>
      <Status></Status>
    </Alert>
    <Alert>
      <ID></ID>
      <Status></Status>
    </Alert>
  </Monitor>
</System>
<System>
  <ID></ID>
  <Name></Name>
  <Monitor>
    <ID></ID>
    <Type></Type>
    <Alert>
      <ID></ID>
      <Status></Status>
    </Alert>
  </Monitor>
</System>

このまま横断したい

XElement xmlDoc = XElement.Load(@"xml");
var q = from el in xmlDoc.Elements("System") select el;

foreach(el in q) {
    Console.WriteLine(el.ID);
    Console.WriteLine(el.Name);

    if (el.Monitor) {
        foreach (mon in el.Monitor) {
            Console.WriteLine(el.ID);
            Console.WriteLine(el.Type);

            if (mon.Alert) {
                foreach (alert in mon.Alert) {
                    Console.WriteLine(alert.ID);
                    Console.WriteLine(alert.Status);
                }
            }
        }
    }
}

現在、私はそれぞれ数回ループし、 if を使用してフィールドをチェックし、値を変数に代入しています。次に、もう一度ループする必要があります。もっと簡単な方法はありますか?プレーンな LINQ または LINQ-TO-XML を使用する必要がありますか?

4

3 に答える 3

0

そのようにトラバースしたい場合は、次のことができます。

var xml = @"
<Root>
<System>
<ID>1</ID>
<Name>One</Name>
<Monitor>
    <ID>2</ID>
    <Type>Two</Type>
    <Alert>
    <ID>3</ID>
    <Status>Three</Status>
    </Alert>
    <Alert>
    <ID>4</ID>
    <Status>Four</Status>
    </Alert>
</Monitor>
</System>
<System>
<ID>5</ID>
<Name>Five</Name>
<Monitor>
    <ID>6</ID>
    <Type>Six</Type>
    <Alert>
    <ID>7</ID>
    <Status>Seven</Status>
    </Alert>
</Monitor>
</System>
</Root>
";

XElement xmlDoc = XElement.Parse(xml);
var q = xmlDoc.Elements("System");

foreach(var el in q) {
    Console.WriteLine(el.Element("ID").Value);
    Console.WriteLine(el.Element("Name").Value);

    foreach(var mon in el.Elements("Monitor")) {
        Console.WriteLine(mon.Element("ID").Value);
        Console.WriteLine(mon.Element("Type").Value);

        foreach(var alert in mon.Elements("Alert")) {
            Console.WriteLine(alert.Element("ID").Value);
            Console.WriteLine(alert.Element("Status").Value);
        }
    }
}
于 2013-09-28T14:48:47.133 に答える
0

このコードを試してください(説明については、以下のコードを参照してください)

    class Program {
        static void Main(string[] args) {
            var xml = @"
<Root>
  <System>
    <ID>1</ID>
    <Name>one</Name>
    <Monitor>
      <ID>3</ID>
      <Type>t3</Type>
      <Alert>
        <ID>5</ID>
        <Status>a5</Status>
      </Alert>
      <Alert>
        <ID>6</ID>
        <Status>a6</Status>
      </Alert>
    </Monitor>
  </System>
  <System>
    <ID>2</ID>
    <Name>two</Name>
    <Monitor>
      <ID>4</ID>
      <Type>t4</Type>
      <Alert>
        <ID>7</ID>
        <Status>a7</Status>
      </Alert>
    </Monitor>
  </System>
</Root>
";
            XElement xmlDoc = XElement.Parse(xml);
            // set q to an enumeration of XElements
            // where the elements xname is "System"
            // the query actually executes the first time q is used
            var q = xmlDoc.Elements("System");
            foreach (var ele in q) {
                // Get the value of the Element with the xname of "ID"
                Console.WriteLine(ele.Element("ID").Value); 
                Console.WriteLine(ele.Element("Name").Value);
                // if ele.Elements("Monitor") returns nothing
                // then the foreach will be skipped (null-execution)
                foreach (var mon in ele.Elements("Monitor")) {
                    Console.WriteLine(mon.Element("ID").Value);
                    Console.WriteLine(mon.Element("Type").Value);
                    foreach (var alert in mon.Elements("Alert")) {
                        Console.WriteLine(alert.Element("ID").Value);
                        Console.WriteLine(alert.Element("Status").Value);
                        }
                    }
                }
            }
        }

このコードは、XML ドキュメントを 1 回だけ移動します。C# では、LINQ には言語要素 (「select」や「from」など) とライブラリ要素 (XDocument.Elements などの .NET フレームワーク メソッド) の両方が含まれます。2 つを混在させることは問題ありませんが、ステートメントの背後で何が起こっているかを理解している場合にのみ行う必要があります。この場合、XDocument が "System" の XName を持つすべての子要素を返すように要求しています。上記のコードでは、「q」はすべての要素を受け取るのではなく、反復可能な列挙を受け取ります。XDocument の内容は最初の foreach まで横断的ではなく、一度に 1 つの要素のみが検査されるため、q の割り当ては非常に低コストの操作です。これがどのように実装されているかを確認するには、「C# yield return」を検索してください。

「アラート」要素のみに関心がある場合は、次のようにすることができます。

var alerts = xmlDoc.Descendants("Alert")

これは、XName が "Alert" のすべての要素の列挙を返します (XML ドキュメントの階層内の場所に関係なく)。階層を確実にしたい場合は、「where」を使用できます。次に例を示します。

var alerts = xmlDoc.Descendants("Alert")
                   .Where(ele => (ele.Parent != null) && (ele.Parent.Name == "Monitor"))
                   .Where(ele => (ele.Parent.Parent != null) && (ele.Parent.Parent.Name == "System"));
foreach (var alert in alerts) {
    Console.WriteLine(alert.Element("ID").Value);
    Console.WriteLine(alert.Element("Status").Value);
    }

同じノードを複数回反復する必要がある場合は、列挙をリストまたは配列に変換することを検討する必要があります。これにより、時間は節約されますが、メモリ使用量が増加します。IEnumerable<> には、この目的のために ".ToArray()" および ".ToList()" という拡張メソッドがあります。

于 2013-09-28T16:14:01.810 に答える
0

C# は OOP 言語です。これを利用する必要があると思います。

例:

public class MySystem
{
    public int Id { get; private set; }
    public string Name { get; private set; }

    public MyMonitor[] Monitors { get; private set; }

    public MySystem(XElement x)
    {
        Id = (int)x.Element("ID");
        Name = x.Element("Name").Value;
        // a little confusing from your code if there can be more than one Monitor
        Monitors = x.Elements("Monitor").Select(m => new MyMonitor(m)).ToArray();
    }
}

Monitor クラスと Alert クラスに対して同様のことを行います。System という名前のクラスはめちゃくちゃなので、MySystem と名付けました。

上記のモニターの配列を作成したように、システムの配列を作成します。

XElement xmlDoc = XElement.Load(@"xml");
MySystem[] systems = xmlDoc.Elements("System")
                           .Select(s => new MySystem(s))
                           .ToArray();

これで、使いやすいクラスにすべての値が格納されました。

于 2013-09-28T18:32:27.953 に答える