【问题标题】:parse the xml by specifying the attribute names通过指定属性名称来解析 xml
【发布时间】:2017-06-23 16:02:23
【问题描述】:

我有一个 xml,我只想从中解析特定属性而不是全部。我有 100 多个属性,我提供的 xml 是一个带有少量属性的示例 .我想明确指定属性名称并解析它们的值。 例如:我想解析获取属性名称 PersonN 、 VerifiedHuman 的值 在我的逻辑中,我想通过指定 <Name>PersonN</Name> 之类的属性名称来解析值并解析它的值 结果应该是 csv。

<InterConnectResponse>
  <SchemaVersion>2.0</SchemaVersion>
  <ConsumerSubjects>
    <ConsumerSubject subjectIdentifier="Primary">
      <DataSourceResponses>
      <RiskViewProducts>
          <RiskViewAttribResponse>
          <Attributes>
                <Attribute>
                  <Name>PersonN</Name>
                  <Value>3</Value>
                </Attribute>
                <Attribute>
                  <Name>VerifiedHuman</Name>
                  <Value>2</Value>
                </Attribute>
                <Attribute>
                  <Name>CurrAddrBlockIndex</Name>
                  <Value>0.61</Value>
                </Attribute>
           ------ Many More Attributes ---------
         </Attributes>
         </RiskViewAttribResponse>
     </RiskViewProducts>
     </DataSourceResponses>
    </ConsumerSubject>
  </ConsumerSubjects>
</InterConnectResponse> 

我正在使用的逻辑:(我不知道如何指定属性名称并获取它们的值)在这段代码中str3是上面的xml。

using (XmlReader read = XmlReader.Create(new StringReader(str3)))
{

    bool isValue = false;
    while (read.Read())
    {
        if (read.NodeType == XmlNodeType.Element && read.Name == "Value")
        {
            isValue = true;
        }

        if (read.NodeType == XmlNodeType.Text && isValue)
        {
            output.Append((output.Length == 0 ? "" : ", ") + read.Value);
            isValue = false;
        }
    }

}

预期输出:

3, 2

【问题讨论】:

  • 请注意,您所说的“属性”并不是 XML 中通常所说的属性。你可能无法控制它,但至少值得意识到它令人困惑。
  • 如果有多个ConsumerSubject元素,你想做什么?

标签: c# xml linq-to-xml


【解决方案1】:

获取字典中的所有值很容易。然后你可以只提取你想要的。使用 xml linq

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;


namespace ConsoleApplication63
{
    class Program
    {
        const string XML_FILENAME = @"c:\temp\test.xml";
        const string CSV_FILENAME = @"c:\temp\test.csv";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(XML_FILENAME);

            Dictionary<string, string> dict = doc.Descendants("Attribute")
                .GroupBy(x => (string)x.Element("Name"), y => (string)y.Element("Value"))
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());

            StreamWriter writer = new StreamWriter(CSV_FILENAME);


            string[] attributesToRead = new[] { "CurrAddrTaxValue", "CurrAddrTaxMarketValue", "PrevAddrTaxValue" };
            //foreach (string attribute in attributesToRead)
            //{
            //    writer.WriteLine(string.Join(",", new string[] { attribute, dict[attribute] }));
            //}

            //all on one line

            string output = string.Join(",", attributesToRead.Select(x => dict[x]).ToArray());
            writer.WriteLine(output);

            writer.Flush();
            writer.Close();
        }
    }

}

【讨论】:

  • 如何从字典中获取值到 csv 文件中?
  • 我真的很喜欢这个答案。但是如何仅将特定键的值放入 csv 文件中?在我的 csv 文件中,我只需要用逗号分隔的单行中的值。我正在寻找一些代码,例如 var attributesToRead = new[] { "CurrAddrTaxValue", "CurrAddrTaxMarketValue", "PrevAddrTaxValue"}; foreach (KeyValuePair&lt;string, string&gt; row in dict.AsEnumerable()) { writer.Write(string.Join("," row.Value)) Where(row.key=&gt; attributesToRead.Contains(ro); } Example output : 3 , 2
  • 这给了我这样的输出(在 3 个单独的行中):CurrAddrTaxValue,3 CurrAddrTaxMarketValue,2 PrevAddrTaxValue,0 但我期待像:3, 2, 0 我只想要值和它们在一行中。抱歉这么具体..我正在尝试自动化一个巨大的过程,这是它的一部分
  • 再次更新代码,但不喜欢它。不是很健壮,阅读很容易出错。
  • 工作就像一个魅力!
【解决方案2】:

如果您想按产品对属性进行分组,您可以执行以下操作。

var document = XDocument.Load(fileName); // or `= XDocument.Parse(xml);`
var attributesToRead = new[] {"PersonN", "VerifiedHuman"};
var productsElements = document.XPathSelectElements("InterConnectResponse/ConsumerSubjects/ConsumerSubject/DataSourceResponses/RiskViewProducts");
var products = productsElements.Select(product => new
{
    Attributes = product.XPathSelectElements("RiskViewAttribResponse/Attributes/Attribute").Select(attribute => new
    {
        Name = attribute.Element("Name")?.Value,
        Value = attribute.Element("Value")?.Value
    }).Where(attribute => attributesToRead.Contains(attribute.Name))
});

要获得所需的输出,您可以这样做。

foreach (var product in products)
{
    foreach (var attribute in product.Attributes)
    {
        Console.WriteLine(attribute.Value + ", ");
    }
}

要创建 csv,我建议您使用 CsvHelper 之类的库。

using (var writer = new StreamWriter(new FileStream(@"C:\mypath\myfile.csv", FileMode.Append)))
{
    var csv = new CsvWriter(writer);
    csv.Configuration.Delimiter = ",";
    foreach (var product in products)
    {
        foreach (var attribute in product.Attributes)
        {
            csv.WriteField(attribute.Value);
        }
        csv.NextRecord();
    }
}

【讨论】:

  • 这个方法会解析出所有的属性。我想指定要解析的属性..
  • 但是,如果我解析几个 xml,这个 csv 会覆盖写入。我如何将数据附加到它?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-13
  • 2015-07-08
  • 2012-06-08
相关资源
最近更新 更多