1

私は、任意のXML を逆シリアル化する機能を必要とする一般的なシステムに取り組んでいます。つまり、XML ドキュメントに含まれるタグ/属性が事前にわかりません。理想的には、XML は次のようになります。

<a att="1">
  <b />
</a>

次のようなオブジェクトになります。

new Tag { name = "a", 
  attributes = new Dictionary<string,string> {{"att", "1"}},
  elements = new List<Tag> { new Tag { name = "b" } } }

すべてが文字列に逆シリアル化されていれば問題ありません。

4

2 に答える 2

2

示唆されているように、LINQ to XMLを使用すると、任意の XML ファイルからデータを解析して抽出できます。

var xml = @"<?xml version=""1.0"" encoding=""utf-8""?><a id=""1"" name=""test"">an element<b>with sub-element</b></a>";
// load XML from string
var xmlDocument = XDocument.Parse(xml);
// OR load XML from file
//var xmlDocument = XDocument.Load(@"d:\temp\input.xml");
// find all elements of type b and in this case take the first one
var bNode = xmlDocument.Descendants("b").FirstOrDefault();
if (bNode != null)
{
    Console.WriteLine(bNode.Value);
}
// find the first element of type a and take the attribute name (TODO error handling)
Console.WriteLine(xmlDocument.Element("a").Attribute("name").Value);

出力は次のとおりです。

with sub-element
test

オブジェクトを XML ファイルに簡単に変換することもできます。

// sample class
public class Entry
{
    public string Name { get; set; }
    public int Count { get; set; }
}

// create and fill the object
var entry = new Entry { Name = "test", Count = 10 };
// create xml container
var xmlToCreate = new XElement("entry", 
                    new XAttribute("count", entry.Count),
                    new XElement("name", entry.Name));
// and save it
xmlToCreate.Save(@"d:\temp\test.xml");

新しく作成された XML ファイルは次のようになります。

<?xml version="1.0" encoding="utf-8"?>
<entry count="10">
  <name>test</name>
</entry>

LINQ は非常に強力で使いやすい (そして IMO 直感的) です。この MSDN の記事では、優れたサンプルを通じて、LINQ とそのさまざまな機能と能力についての優れた洞察が得られます。LINQPad - ミニマルだが非常に強力な .NET 用 IDE には、非常に優れた組み込みの LINQ to XML チュートリアルと例が付属しています。最後に、MSDN にあるすべての LINQ to XML 拡張メソッドのリストを次に示します。

もう 1 つの可能性は、XmlReader クラスを使用して任意の XML ファイルを解析することです。ここでは、解析ロジックを実装する責任があるため、面倒な場合があります。XmlReader を使用して同じ入力ファイルを解析すると、次のようになります。

public void parseUsingXmlReader(string xmlString)
{
    using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
    {
        XmlWriterSettings ws = new XmlWriterSettings();
        ws.Indent = true;
        while (reader.Read())
        {
            switch (reader.NodeType)
            {
                case XmlNodeType.Element:
                    Console.WriteLine(string.Format("Element - {0}", reader.Name));
                    if (reader.HasAttributes)
                    {
                        for (var i = 0; i < reader.AttributeCount; i++)
                        {
                            Console.WriteLine(string.Format("Attribute - {0}", reader.GetAttribute(i)));
                        }
                        reader.MoveToElement();
                    }
                    break;
                case XmlNodeType.Text:
                    Console.WriteLine(string.Format("Element value - {0}", reader.Value));
                    break;
                //case XmlNodeType.XmlDeclaration:
                //case XmlNodeType.ProcessingInstruction:
                //  Console.WriteLine(reader.Name + " - " + reader.Value);
                //  break;
                case XmlNodeType.Comment:
                    Console.WriteLine(reader.Value);
                    break;
                case XmlNodeType.EndElement:
                    Console.WriteLine(reader.Value);
                    break;
            }
        }
    }
}
// use the new function with the input from the first example
parseUsingXmlReader(xml);

出力は次のとおりです。

Element - a
Attribute - 1
Attribute - test
Element value - an element
Element - b
Element value - with sub-element

ご覧のとおり、ノードの種類、現在の位置、属性などを手動で処理する必要があります。

于 2013-11-03T19:59:00.480 に答える
0

ここには多くの情報はありません。Linq for XML アプローチの代替外部インターフェイスとして、動的アプローチを試すことができます。以下にプログラム例を示します。

class Program {
    static void Main(string[] args) {
        var xmlstr = 
@"<a att='1'>
    <b attb='a b c'>
      <c att2='text'>value</c>
    </b>
</a>";
        dynamic xml = new DynamicXml(xmlstr);
        Console.WriteLine(xml.a[0].att);
        Console.WriteLine(xml.a[0].b[0].attb);
        Console.WriteLine(xml.a[0].b[0].c[0].att2);

        }

    public class DynamicXml: DynamicObject {
        XElement _root;
        IEnumerable<XElement> _xele;

        public DynamicXml(string xml) {
            var xdoc = XDocument.Parse(xml);
            _root = xdoc.Root;
            }

        DynamicXml(XElement root) {
            _root = root;
            }

        DynamicXml(XElement root, IEnumerable<XElement> xele) {
            _root = root;
            _xele = xele;
            }

        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) {
            // you should check binder.CallInfo, but for the example I'm assuming [n] where n is int type indexing
            var idx = (int)indexes[0];
            result = new DynamicXml(_xele.ElementAt(idx));
            return true;
            }

        public override bool TryGetMember(GetMemberBinder binder, out object result) {
            var atr = _root.Attributes(binder.Name).FirstOrDefault();
            if (atr != null) {
                result = atr.Value;
                return true;
                }
            var ele = _root.DescendantsAndSelf(binder.Name);
            if (ele != null) {
                result = new DynamicXml(_root, ele);
                return true;
                }
            result = null;
            return false;
            }
        }
    }

ここで注意すべきことは、XML 要素には属性だけでなく値も含めることができるということです。値を処理する方法が必要です。上記のコードでは、「Value」などの特別な名前を使用できますが、同じ名前の属性を処理することはできません。

于 2013-11-03T21:09:52.640 に答える