面对从数据创建的XML结构中的问题

时间:2013-02-15 06:31:44

标签: c# xml xml-serialization

我想通过数据创建XML,并且我从DataSetIList<Booking>的数据库收到数据。 现在我正在使用DataSet通过此代码创建XML。

string result = String.Empty;

using (StringWriter sw = new StringWriter())
 {
   ds.WriteXml(sw);
   result = sw.ToString();
 }

我的XML就是这种形式。

<Booking> 
    <ID>32</ID> 
    <BookingNumber>12120001</BLNumber> 
    <ReferenceNo>ABCED11212280007</ReferenceNo> 
    <Name>Customer Name1</Name> 
    <Address>Customer Address</Address>
</Booking>

<Booking> 
    <ID>33</ID> 
    <BookingNumber>12120002</BLNumber> 
    <ReferenceNo>ABCED11212280008</ReferenceNo> 
    <Name>Customer Name2</Name> 
    <Address>Customer Address2</Address>
</Booking>



<BookingDetail> 
   <ID>206</ID> 
   <BookingID>32</BookingID> 
   <OrderItem>Item1</OrderItem> 
</BookingDetail>

<BookingDetail> 
   <ID>207</ID> 
   <BookingID>32</BookingID> 
   <OrderItem>Item2</OrderItem> 
</BookingDetail>

<BookingDetail> 
   <ID>208</ID> 
   <BookingID>33</BookingID> 
   <OrderItem>Item1</OrderItem> 
</BookingDetail>

<BookingDetail> 
   <ID>209</ID> 
   <BookingID>33</BookingID> 
   <OrderItem>Item2</OrderItem> 
</BookingDetail>

<BookingDetail> 
   <ID>210</ID> 
   <BookingID>33</BookingID> 
   <OrderItem>Item3</OrderItem> 
</BookingDetail>

但我想要这种形式的XML。

<CompleteBooking>
 <Booking> 
    <ID>32</ID> 
    <BookingNumber>12120001</BLNumber> 
    <ReferenceNo>ABCED11212280007</ReferenceNo> 
    <Name>Customer Name1</Name> 
    <Address>Customer Address</Address>
 </Booking>

 <BookingDetail> 
   <ID>206</ID> 
   <BookingID>32</BookingID> 
   <OrderItem>Item1</OrderItem> 
 </BookingDetail>

 <BookingDetail> 
   <ID>207</ID> 
   <BookingID>32</BookingID> 
   <OrderItem>Item2</OrderItem> 
 </BookingDetail>

</CompleteBooking>

<CompleteBooking>
 <Booking> 
    <ID>33</ID> 
    <BookingNumber>12120002</BLNumber> 
    <ReferenceNo>ABCED11212280008</ReferenceNo> 
    <Name>Customer Name2</Name> 
    <Address>Customer Address2</Address>
 </Booking>

 <BookingDetail> 
   <ID>208</ID> 
   <BookingID>33</BookingID> 
   <OrderItem>Item1</OrderItem> 
 </BookingDetail>

 <BookingDetail> 
   <ID>209</ID> 
   <BookingID>33</BookingID> 
   <OrderItem>Item2</OrderItem> 
 </BookingDetail>

 <BookingDetail> 
   <ID>210</ID> 
   <BookingID>33</BookingID> 
   <OrderItem>Item3</OrderItem> 
 </BookingDetail>

</CompleteBooking>

任何人都可以帮我创建这种类型的XML吗?

6 个答案:

答案 0 :(得分:5)

使用System.Xml.Serialization,创建预订对象:

public class XMLEntities
{   
  [XmlRoot(ElementName = "CompleteBooking")]
  public class CompleteBooking
  {
    [XmlElement(ElementName = "Booking")]
    public Booking Bookings { get; set; }

    [XmlElement(ElementName = "BookingDetail")]
    public List<BookingDetail> BookingDetail { get; set; }
  }

  public class Booking
  {
    [XmlElement("ID")]
    public int ID { get; set; }

    [XmlElement("BookingNumber")]
    public int BookingNumber { get; set; }

    [XmlElement("ReferenceNumber")]
    public string ReferenceNumber { get; set; }

    [XmlElement("Name")]
    public string Name { get; set; }

    [XmlElement("Address")]
    public string Address { get; set; }
  }

  public class BookingDetail
  {
    [XmlElement("ID")]
    public int ID { get; set; }

    [XmlElement("BookingID")]
    public int BookingID { get; set; }

    [XmlElement("OrderItem")]
    public string OrderItem { get; set; }
  }
}

现在,对于序列化程序对象(用于将对象实际序列化为字符串):

 public class XMLEntitiesSerializer
 {
   public string Serialize(XMLEntities.CompleteBooking completeBooking)
   {
     var serializedXml = string.Empty;

     var serializer = new XmlSerializer(typeof (XMLEntities.CompleteBooking));
     var stringWriter = new System.IO.StringWriter();

     try
     {
       serializer.Serialize(stringWriter, completeBooking);
       serializedXml = stringWriter.ToString();
     }
     catch(Exception ex)
     {
       //Log the stuff
     }
     finally
     {
       stringWriter.Close();
     }

     return serializedXml;
   }
 }

现在,您只需创建正确定义的对象并在某种函数中进行序列化。例如,在控制台应用程序的主要方法中:

public static void Main(string[] args)
{
  //Create new booking objects
  var booking1 = new XMLEntities.Booking()
                  {
                    ID = 32,
                    BookingNumber = 1212001,
                    ReferenceNumber = "ABCED11212280007",
                    Name = "Customer Name1",
                    Address = "Customer Address"
                  };
  var booking2 = new XMLEntities.Booking()
                   {
                     ID = 33,
                     BookingNumber = 12120002,
                     ReferenceNumber = "ABCED11212280008",
                     Name = "Customer Name2",
                     Address = "Customer Address2"
                   };

  //Create the booking details objects

  var booking1Detail1 = new XMLEntities.BookingDetail()
                         {
                           ID = 206,
                           BookingID = 32,
                           OrderItem = "Item1"
                         };
  var booking1Detail2 = new XMLEntities.BookingDetail()
                          {
                            ID = 207,
                            BookingID = 32,
                            OrderItem = "Item2"
                          };

  var booking2Detail1 = new XMLEntities.BookingDetail()
                          {
                            ID = 208,
                            BookingID = 33,
                            OrderItem = "Item1"
                          };
  var booking2Detail2 = new XMLEntities.BookingDetail()
                          {
                            ID = 209,
                            BookingID = 32,
                            OrderItem = "Item2"
                          };
  var booking2Detail3 = new XMLEntities.BookingDetail()
                          {
                            ID = 210,
                            BookingID = 32,
                            OrderItem = "Item3"
                          };

  //Smash them together so we can serialize as one

  var completeBooking1 = new XMLEntities.CompleteBooking()
                          {
                            Bookings = booking1,
                            BookingDetail = new List<XMLEntities.BookingDetail>()
                                              {
                                                booking1Detail1,
                                                booking1Detail2
                                              }
                          };
  var completeBooking2 = new XMLEntities.CompleteBooking()
                           {
                             Bookings = booking2,
                             BookingDetail = new List<XMLEntities.BookingDetail>()
                                               {
                                                 booking2Detail1,
                                                 booking2Detail2,
                                                 booking2Detail3
                                               }
                           };

  //Serialize the data for each of the booking objects

  var serializedXML = new XMLEntitiesSerializer();
  var xml = string.Empty;

  var booking1XmlString = serializedXML.Serialize(completeBooking1);
  var booking2XmlString = serializedXML.Serialize(completeBooking2);

  Console.ReadLine();
}

显然,你可以在重构函数中使用它(这会让生活更轻松),但是这会为你提供你想要的一般输出。

答案 1 :(得分:3)

这是一种可行的方法:

        DataTable Booking = new DataTable();
        Booking.Columns.AddRange(new DataColumn[]{ new DataColumn("ID"), new DataColumn("BookingNumber"), new DataColumn("ReferenceNo"), new DataColumn("Name"), new DataColumn("Address") });

        DataTable BookingDetail = new DataTable();
        BookingDetail.Columns.AddRange(new DataColumn[] { new DataColumn("ID"), new DataColumn("BookingID"), new DataColumn("OrderItem") });

        Booking.Rows.Add(32, 12120001, "ABCED11212280007", "Customer Name1", "Customer Address");
        BookingDetail.Rows.Add(206, 32, "Item1");
        BookingDetail.Rows.Add(207, 32, "Item2");

        Booking.Rows.Add(33, 12120002, "ABCED11212280008", "Customer Name2", "Customer Address2");
        BookingDetail.Rows.Add(208, 33, "Item1");
        BookingDetail.Rows.Add(209, 33, "Item2");
        BookingDetail.Rows.Add(210, 33, "Item3");

        XElement root = new XElement("Root");

        // For each row from Booking add one CompleteBooking element
        foreach(DataRow BookingRow in Booking.Rows.Cast<DataRow>())
        {
            XElement xeCompleteBooking = new XElement("CompleteBooking");

            XElement xeBooking = new XElement("Booking");
            int BookingID = Convert.ToInt32(BookingRow["ID"]);

            IEnumerable<string> columnNames_Booking = Booking.Columns.Cast<DataColumn>().Select(col => col.ColumnName);
            // Add element under Booking element for every column of table
            foreach (string colName in columnNames_Booking)
                xeBooking.Add(new XElement(colName, BookingRow[colName]));

            xeCompleteBooking.Add(xeBooking);

            IEnumerable<string> columnNames_BookingDetail = BookingDetail.Columns.Cast<DataColumn>().Select(col => col.ColumnName);

            // For Booking.ID find all BookingDetail rows according to BookingDetail.BookingID
            IEnumerable<DataRow> details = BookingDetail.Rows.Cast<DataRow>().Where(BookingDetailRow => Convert.ToInt32(BookingDetailRow["BookingID"]) == BookingID);
            foreach (DataRow BookingDetailRow in details)
            {
                XElement xeBookingDetail = new XElement("BookingDetail");

                // Add element under BookingDetail element for every column of table
                foreach (string colName in columnNames_BookingDetail)
                    xeBookingDetail.Add(new XElement(colName, BookingDetailRow[colName]));

                xeCompleteBooking.Add(xeBookingDetail);
            }

            root.Add(xeCompleteBooking);
        }

        string xml = root.ToString();

它使用LINQ to XML。它读取列名称以创建适当命名的XML元素,因此如果您在表中添加或删除某些列不应该分解,那么应该具有固定列名称的唯一列是IDBooking )和BookingIDBookingDetail),因为它们用于链接两个表。

答案 2 :(得分:2)

您是否可以在数据对象上使用XmlSerializer类?或者我误解了这个问题?

没有看到一些对象结构,除了提供一些“如果我在你的鞋子里......”之外我几乎无能为力。

你想要的是“非标准”XML,因为当一个是列表(BookingDetail)时,你在同一标签下有两种类型的对象“Booking”和“BookingDetail”。

如果必须采用这种形式,我的方法是手动序列化:

public String Serialize(CompleteBooking [] cbs) {
    String FinalXML = "<CompleteBookings>";
    foreach(CompleteBooking cb in cbs) {
        FinalXML += cb.ToXML();
    }
    FinalXML += "</CompleteBookings>";
}

数据对象:

public class CompleteBooking {
    public Booking Booking;
    public BookingDetail [] BookingDetails

    public String ToXML() {
        String RVal = "<CompleteBooking>" + this.Booking.ToXML();
        foreach(BookingDetail bd in BookingDetails) {
            RVal += bd.ToXML();
        }
        RVal += "</CompleteBooking>"


    }
}

public class Booking {
    // Fields Here
    public String ToXML() {
        return "<Booking>" + [Fields] + "</Booking>";
    }
}

public class BookingDetail {
    // Fields Here
    public String ToXML() {
        return "<BookingDetail>" + [Fields] + "</BookingDetail>";
    }
}

答案 3 :(得分:2)

假设我们有以下数据类:

class Booking
{
    public int ID { get; set;}
    public int BookingNumber { get; set;}
    public string ReferenceNo { get; set;}
    public string Name { get; set;}
    public string Address { get; set;}
}

class BookingDetails
{
    public int ID { get; set;}
    public int BookingId { get; set;}
    public string OrderItem { get; set;}
}

以下测试数据:

    static private IList<Booking> _bookings = new List<Booking>() {
        new Booking() { ID = 32, BookingNumber = 12120001, ReferenceNo = "ABCED11212280007", Name = "Customer Name1", Address = "Customer Address" },
        new Booking() { ID = 33, BookingNumber = 12120002, ReferenceNo = "ABCED11212280008", Name = "Customer Name2", Address = "Customer Address2" }
    };

    static private IList<BookingDetails> _details = new List<BookingDetails>() {
        new BookingDetails() { ID = 206, BookingId = 32, OrderItem = "Item1" },
        new BookingDetails() { ID = 207, BookingId = 32, OrderItem = "Item2" },
        new BookingDetails() { ID = 208, BookingId = 33, OrderItem = "Item1" },
        new BookingDetails() { ID = 209, BookingId = 33, OrderItem = "Item2" },
        new BookingDetails() { ID = 210, BookingId = 33, OrderItem = "Item3" }
    };

我们可以使用以下Linq to XML查询轻松获取给定格式的输出XML:

var bookings = _bookings.Join(_details, b => b.ID, d => d.BookingId, (b, d) => new { b, d })
                        .GroupBy(g => g.b, g => g.d)
                        .Select(g => new XElement("CompleteBooking",
                                        new XElement("Booking", 
                                            new XElement("ID", g.Key.ID),
                                            new XElement("BookingNumber", g.Key.BookingNumber),
                                            new XElement("ReferenceNo", g.Key.ReferenceNo),
                                            new XElement("Name", g.Key.Name),
                                            new XElement("Address", g.Key.Address)),
                                        g.Select(d => new XElement("BookingDetail",
                                                            new XElement("ID", d.ID),
                                                            new XElement("BookingID", d.BookingId),
                                                            new XElement("OrderItem", d.OrderItem))).ToArray())).ToArray();

它会给我们一个XElement对象数组。要使用String.Join<XElement>方法获取xml字符串:

var xmlString = String.Join<XElement>(Environment.NewLine, bookings);

但是,我建议使用一些不同的XML架构:

<Bookings>
  <Booking>
    <ID>32</ID>
    <BookingNumber>12120001</BookingNumber>
    <ReferenceNo>ABCED11212280007</ReferenceNo>
    <Name>Customer Name1</Name>
    <Address>Customer Address</Address>
    <Details>
      <Detail>
        <ID>206</ID>
        <OrderItem>Item1</OrderItem>
      </Detail>
      <Detail>
        <ID>207</ID>
        <OrderItem>Item2</OrderItem>
      </Detail>
    </Details>
  </Booking>
  <Booking>
    <ID>33</ID>
    <BookingNumber>12120002</BookingNumber>
    <ReferenceNo>ABCED11212280008</ReferenceNo>
    <Name>Customer Name2</Name>
    <Address>Customer Address2</Address>
    <Details>
      <Detail>
        <ID>208</ID>
        <OrderItem>Item1</OrderItem>
      </Detail>
      <Detail>
        <ID>209</ID>
        <OrderItem>Item2</OrderItem>
      </Detail>
      <Detail>
        <ID>210</ID>
        <OrderItem>Item3</OrderItem>
      </Detail>
    </Details>
  </Booking>
</Bookings>

这种格式的数据没有冗余。要使用以下查询:

var bookings = _bookings.Join(_details, b => b.ID, d => d.BookingId, (b, d) => new { b, d })
                        .GroupBy(g => g.b, g => g.d)
                        .Select(g => new XElement("Booking", 
                                        new XElement("ID", g.Key.ID),
                                        new XElement("BookingNumber", g.Key.BookingNumber),
                                        new XElement("ReferenceNo", g.Key.ReferenceNo),
                                        new XElement("Name", g.Key.Name),
                                        new XElement("Address", g.Key.Address),
                                        new XElement("Details",
                                            g.Select(d => new XElement("Detail",
                                                              new XElement("ID", d.ID),
                                                              new XElement("OrderItem", d.OrderItem))).ToArray()))).ToArray();

var data = new XDocument(new XElement("Bookings", bookings));

答案 4 :(得分:1)

您可以使用LINQ to XML创建自定义结构。使用嵌套的XElement构造函数。例如,请参阅How to create an XML of this structureBuild XML Dynamically using c#

答案 5 :(得分:1)

对于迟到的回答来回答我对您的问题的评论,@ Umair Noor。

由于您使用的是.NET DataSet,因此这是我所知道的最简单的方法,可以从中获取所需的XML - 以及相关的在线参考:

  1. 创建一个表示您希望查看的XML输出的XML文档。 您已经在中完成了您将需要1)用<\BLNumber>标记替换<\BookingNumber>结束标记和2)地址@ ByteBlast关于样本中多个根元素的观点。

    通过最低限度地调整您想要的XML示例,我最终得到了以下内容:

    <Bookings> <!-- fix for multiple root elements -->
      <CompleteBooking>
        <Booking>
          <ID>32</ID>
          <BookingNumber>12120001</BookingNumber> <!-- fixed BLNumber closing tag -->
          <ReferenceNo>ABCED11212280007</ReferenceNo>
          <Name>Customer Name1</Name>
          <Address>Customer Address</Address>
        </Booking>
    
        <BookingDetail>
          <ID>206</ID>
          <BookingID>32</BookingID>
          <OrderItem>Item1</OrderItem>
        </BookingDetail>
    
        <BookingDetail>
          <ID>207</ID>
          <BookingID>32</BookingID>
          <OrderItem>Item2</OrderItem>
        </BookingDetail>
    
      </CompleteBooking>
    
      <CompleteBooking>
        <Booking>
          <ID>33</ID>
          <BookingNumber>12120002</BookingNumber> <!-- fixed BLNumber closing tag -->
          <ReferenceNo>ABCED11212280008</ReferenceNo>
          <Name>Customer Name2</Name>
          <Address>Customer Address2</Address>
        </Booking>
    
        <BookingDetail>
          <ID>208</ID>
          <BookingID>33</BookingID>
          <OrderItem>Item1</OrderItem>
        </BookingDetail>
    
        <BookingDetail>
          <ID>209</ID>
          <BookingID>33</BookingID>
          <OrderItem>Item2</OrderItem>
        </BookingDetail>
    
        <BookingDetail>
          <ID>210</ID>
          <BookingID>33</BookingID>
          <OrderItem>Item3</OrderItem>
        </BookingDetail>
    
      </CompleteBooking>
    </Bookings> <!-- fix for multiple root elements -->
    
  2. 使用xsd.exe command-line tool从代表性XML文件生成XML架构定义(XSD)文件。

    或者,编写几行代码来读取XML文件,使用XmlReadMode.InferSchema为其生成架构;并将生成的模式写入XSD文件。例如,这是我快速投入WPF临时应用程序中的按钮事件处理程序:

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        // BEGIN: the bottom-line logic
        var ds = new DataSet();
    
        var sr = new StreamReader("Bookings.xml"); // file into which I put your sample, desired XML
        ds.ReadXml(sr, XmlReadMode.InferSchema); // XmlReadMode.InferSchema - key
        sr.Close();
    
        ds.WriteXmlSchema("Bookings.xsd"); // file into which I got the resulting schema
        // END: the bottom-line logic
    }
    

    这两种方法都足够快。

  3. 使用XSD文件...

    <?xml version="1.0" standalone="yes"?>
    <xs:schema id="Bookings" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
      <xs:element name="Bookings" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
        <xs:complexType>
          <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element name="CompleteBooking">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="Booking" minOccurs="0" maxOccurs="unbounded">
                    <xs:complexType>
                      <xs:sequence>
                        <xs:element name="ID" type="xs:string" minOccurs="0" />
                        <xs:element name="BookingNumber" type="xs:string" minOccurs="0" />
                        <xs:element name="ReferenceNo" type="xs:string" minOccurs="0" />
                        <xs:element name="Name" type="xs:string" minOccurs="0" />
                        <xs:element name="Address" type="xs:string" minOccurs="0" />
                      </xs:sequence>
                    </xs:complexType>
                  </xs:element>
                  <xs:element name="BookingDetail" minOccurs="0" maxOccurs="unbounded">
                    <xs:complexType>
                      <xs:sequence>
                        <xs:element name="ID" type="xs:string" minOccurs="0" />
                        <xs:element name="BookingID" type="xs:string" minOccurs="0" />
                        <xs:element name="OrderItem" type="xs:string" minOccurs="0" />
                      </xs:sequence>
                    </xs:complexType>
                  </xs:element>
                </xs:sequence>
              </xs:complexType>
            </xs:element>
          </xs:choice>
        </xs:complexType>
      </xs:element>
    </xs:schema>
    

    ...定义键入的DataSet(例如BookingsBookingsDataSet) - 而不是您可能使用的通用DataSet

    您可以将xsd.exe的{​​{1}}选项与步骤3中的XSD文件一起使用,或者您可以在Visual Studio中向项目添加新的/d[ataset]项,然后粘贴该步骤-3-derived模式到其DataSet文件中。

    相同 - 两种方式都足够快。

  4. 根据需要重复,直到获得所需的确切结果。

  5. 对于权威参考,MSDN有a good overview of XML in ADO.NET解释了我所描述的大部分内容。