2

私のプロジェクトでは、入力 XML ファイルを DataTable に変換する機能が必要です。そのために次のコードを使用しています。

 DataSet ds = new DataSet();
 ds.Locale = CultureInfo.InvariantCulture;
 dataSourceFileStream.Seek(0, SeekOrigin.Begin);
 ds.ReadXml(dataSourceFileStream);
 dt = ds.Tables[0];

これは、入力 XML に重複する要素が含まれていない限り (たとえば、XML ファイルが次のようになっている場合)、静かに機能します。

<?xml version="1.0" encoding="iso-8859-1"?>
<DocumentElement>
 <data>
   <DATE>27 September 2013</DATE>
   <SCHEME>Test Scheme Name</SCHEME>
   <NAME>Mr John</NAME>
   <SCHEME>Test Scheme Name</SCHEME>
  <TYPE>1</TYPE>
 </data>
</DocumentElement>

上記のように、要素SCHEMEが 2 回表示されます。この種の XML ファイルが来るds.ReadXml(dataSourceFileStream);と、正しいデータ テーブルが返されません。

これを処理するより良い方法はありますか?

4

2 に答える 2

1

最初に XML を修正する必要があるようです。これは、XDocument および関連するクラスを使用して行うことができます。ただし、最初に、名前に基づいて 2 つの XElement を比較する EqualityComparer を作成する必要があります。

    public class MyEqualityComparer : IEqualityComparer<XElement>
    {
        public bool Equals(XElement x, XElement y)
        {
            return x.Name == y.Name;
        }

        public int GetHashCode(XElement obj)
        {
            return obj.Name.GetHashCode();
        }
    }

これを試してください:

        var comparer = new MyEqualityComparer();

        XDocument.Load(dataSourceFileStream);

        var doc = XDocument.Parse(data);

        var dataElements = doc.Element("DocumentElement").Elements("data");
        foreach (var dataElement in dataElements)
        {
            var childElements = dataElement.Elements();
            var distinctElements = childElements.Distinct(comparer).ToArray();
            if (distinctElements.Length != childElements.Count())
            {
                dataElement.Elements().Remove();
                foreach (var item in distinctElements)
                    dataElement.Add(item);
            }
        }

        using (var stream = new MemoryStream())
        {
            var writer = new StreamWriter(stream);
            doc.Save(writer);

            stream.Seek(0, 0);

            var ds = new DataSet();
            ds.Locale = CultureInfo.InvariantCulture;
            var mode = ds.ReadXml(stream);
            var dt = ds.Tables[0];      
        }

それはあなたの問題に対する迅速な回避策です。しかし、データ プロバイダーに XML を修正するように勧めることを強くお勧めします。

于 2013-09-30T14:40:12.840 に答える
1

わかった。以前のコメントで述べたように、いくつかの要素にパッチを適用/無視する独自の XmlTextReader を作成できます。アイデアは、このリーダーが同じ深さ内の要素を既に読んだかどうかをチェックするということです。その場合は、最後の要素に進みます。

    class MyXmlReaderPatcher : XmlTextReader
    {
        private readonly HashSet<string> _currentNodeElementNames = new HashSet<string>();

        public MyXmlReaderPatcher(TextReader reader) : base(reader)
        { }

        public override bool Read()
        {
            var result = base.Read();

            if (this.Depth == 1)
            {
                _currentNodeElementNames.Clear();
            }
            else if (this.Depth==2 && this.NodeType == XmlNodeType.Element)
            {
                if (_currentNodeElementNames.Contains(this.Name))
                {
                    var name = this.Name;

                    do {
                        result = base.Read();
                        if (result == false)
                            return false;
                    } while (this.NodeType != XmlNodeType.EndElement && this.Name != name);

                    result = this.Read();
                }
                else
                {
                    _currentNodeElementNames.Add(this.Name);
                }
            }

            return result;
        }
    }

ds.ReadXml() とファイル ストリームの間に新しいリーダーをリンクするだけです。

        var myReader = new MyXmlReaderPatcher(dataSourceFileStream);

        var ds = new DataSet();
        ds.Locale = CultureInfo.InvariantCulture;
        var mode = ds.ReadXml(myReader);
        var dt = ds.Tables[0];
于 2013-10-01T15:30:43.227 に答える