如何将多对一XML数据转换为DataSet?

时间:2010-05-19 19:42:38

标签: c# asp.net xml .net-3.5 dataset

我有一个包含对象集合的XML文档。每个对象都有一个键/值对的标签和值。我试图将其转换为DataSet,但是当我执行ds.ReadXml(xmlFile)时,它会创建两列:label和value。

我想要的是为每个“标签”添加一列,并将该值作为该行的一部分。这是我的XML样本:

<responses>
  <response>
    <properties id="1" Form="Account Request" Date="Tuesday, March 16, 2010 5:04:26 PM" Confirmation="True" />
    <fields>
      <field>
        <label>Name</label>
        <value>John</value>
      </field>
      <field>
        <label>Email</label>
        <value>John@Doe.com</value>
      </field>
      <field>
        <label>Website</label>
        <value>http://domain1.com</value>
      </field>
      <field>
        <label>Phone</label>
        <value>999-999-9999</value>
      </field>
      <field>
        <label>Place of Birth</label>
        <value>Earth</value>
      </field>
      <field>
        <label>Misc</label>
        <value>Misc</value>
      </field>
      <field>
        <label>Comments</label>
        <value />
      </field>
      <field>
        <label>Agree to Terms?</label>
        <value>True</value>
      </field>
    </fields>
  </response>
  <response>
    <properties id="2" Form="Account Request" Date="Tuesday, March 17, 2010 5:04:26 PM" Confirmation="True" />
    <fields>
      <field>
        <label>Name</label>
        <value>John2</value>
      </field>
      <field>
        <label>Email</label>
        <value>John2@Doe.com</value>
      </field>
      <field>
        <label>Website</label>
        <value>http://domain2.com</value>
      </field>
      <field>
        <label>Phone</label>
        <value>999-999-9999</value>
      </field>
      <field>
        <label>Place of Birth</label>
        <value>Earth</value>
      </field>
      <field>
        <label>Misc</label>
        <value>Misc</value>
      </field>
      <field>
        <label>Comments</label>
        <value />
      </field>
      <field>
        <label>Agree to Terms?</label>
        <value>True</value>
      </field>
    </fields>
  </response>
  <response>
    <properties id="3" Form="Account Request" Date="Tuesday, March 18, 2010 5:04:26 PM" Confirmation="True" />
    <fields>
      <field>
        <label>Name</label>
        <value>John3</value>
      </field>
      <field>
        <label>Email</label>
        <value>John3@Doe.com</value>
      </field>
      <field>
        <label>Website</label>
        <value>http://domain3.com</value>
      </field>
      <field>
        <label>Phone</label>
        <value>999-999-9999</value>
      </field>
      <field>
        <label>Place of Birth</label>
        <value>Earth</value>
      </field>
      <field>
        <label>Misc</label>
        <value>Misc</value>
      </field>
      <field>
        <label>Comments</label>
        <value />
      </field>
      <field>
        <label>Agree to Terms?</label>
        <value>True</value>
      </field>
    </fields>
  </response>
  <response>
    <properties id="4" Form="Account Request" Date="Tuesday, March 19, 2010 5:04:26 PM" Confirmation="True" />
    <fields>
      <field>
        <label>Name</label>
        <value>John</value>
      </field>
      <field>
        <label>Email</label>
        <value>John4@Doe.com</value>
      </field>
      <field>
        <label>Website</label>
        <value>http://domain4.com</value>
      </field>
      <field>
        <label>Phone</label>
        <value>999-999-9999</value>
      </field>
      <field>
        <label>Place of Birth</label>
        <value>Earth</value>
      </field>
      <field>
        <label>Misc</label>
        <value>Misc</value>
      </field>
      <field>
        <label>Comments</label>
        <value />
      </field>
      <field>
        <label>Agree to Terms?</label>
        <value>True</value>
      </field>
    </fields>
  </response>
</responses>

如何将其转换为DataSet,以便我可以将其加载到带有列的gridview中:名称,电子邮件,网站,电话,出生地,杂项,评论和同意条款?

然后第1行将是: John,John @ Doe.com,http://domain1.com,999-999-9999,Earth,Misc,True

如何使用提供的XML执行此操作?

3 个答案:

答案 0 :(得分:1)

您必须转换数据才能按照自己的方式使用它。如你所见,你的结构很糟糕。

我建议您在Visual Studio中创建一个空数据集(来自Add-&gt; New Item),然后将其设置为您希望它的外观。编写一些代码来添加一些测试数据,然后使用DataSet.WriteXml将其写入文件。这将向您展示您提出的结构的样子。

然后我建议您使用LINQ to XML将输入XML转换为新格式。


以下是使用LINQ to XML转换数据的示例:

public static void TransformIt(TextWriter output)
{
    var inputDocument = XDocument.Parse(INPUT_XML);
    if (inputDocument.Root == null)
    {
        return;
    }

    var doc = new XDocument(
        new XElement(
            "responses",
            from response in inputDocument.Root.Elements()
            select new XElement(
                "response",
                from lv in GetResponseLabels(response)
                select MakeResponse(lv.Label, lv.Value))));

    var settings = new XmlWriterSettings
    {
        Encoding = Encoding.UTF8,
        Indent = true,
    };
    using (var writer = XmlWriter.Create(output, settings))
    {
        if (writer == null)
        {
            return;
        }

        doc.WriteTo(writer);
    }
}

private static XElement MakeResponse(string label, string value)
{
    var trimmedLabel = label.Replace(" ", String.Empty).Replace("?", String.Empty);
    return new XElement(trimmedLabel, value);
}

private static IEnumerable<LabelAndValue> GetResponseLabels(XContainer response)
{
    var fieldsElement = response.Element("fields");
    if (fieldsElement == null)
    {
        return null;
    }

    return from field in fieldsElement.Elements("field")
           let valueElement = field.Element("value")
           let labelElement = field.Element("label")
           select new LabelAndValue
           {
               Label = labelElement == null ? "Unknown" : labelElement.Value,
               Value = valueElement == null ? null : valueElement.Value
           };
}

private struct LabelAndValue
{
    public string Label { get; set; }
    public string Value { get; set; }
}

答案 1 :(得分:0)

我将遍历XML并根据您的迭代方式(Linq最灵活),创建一个新对象(例如,数据表),并以您需要的方式描述您的数据。

答案 2 :(得分:0)

我最后改变了方法并做了这个(支点):

DataRow dr = dt.NewRow();

//TRANSFORM RESPONSE LABELS INTO COLUMNS
foreach (XmlNode fieldNode in currentXml.SelectNodes("response/fields/field"))
{
    string label = fieldNode.SelectSingleNode("label").InnerText ?? "Unknown";
    string value = fieldNode.SelectSingleNode("value").InnerText;
    //CHECK IF ARBITRARY LABEL WAS ADDED BEFORE
    if (!dt.Columns.Contains(label))
    {
        //CREATE COLUMN FOR NEW LABEL
        dt.Columns.Add(label);
    }
    dr[label] = value;
}
dt.Rows.Add(dr);
}
ds.Tables.Add(dt);