2013-02-15 2 views
3

Я хочу создать XML через данные, и у меня есть данные, полученные из базы данных в DataSet или IList<Booking>. Сейчас я использую DataSet для создания XML по этому коду.проблема с обращением в структуре 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?

+1

Вы можете показать свой объект stucture, или это все анонимное из базы данных –

+0

@ sa_ddam213: его приход из непосредственно из базы данных, а также набора данных есть 2 таблицы. –

+1

Вы не можете иметь несколько корневых элементов в допустимом файле XML ... –

ответ

2

Не можете ли вы использовать класс XmlSerializer для своих объектов данных? Или я не понимаю вопрос?

Не видя некоторый объект структуры там мало что могу сделать, кроме как обеспечить некоторые «Если бы я был на вашем месте ...»

То, что вы хотите, это «нестандартными» XML в том, что у вас есть два типа объектов «Бронирование »и« BookingDetail »под одним и тем же тегом, когда один из них является списком (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

Вот один из возможных способов код:

 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-элементов, поэтому, если вы добавляете или удаляете некоторые столбцы из таблицы, это не должно разрушаться, единственными столбцами, которые должны иметь фиксированные имена столбцов, являются ID (Booking) и BookingID (BookingDetail), поскольку они используются для связывания двух таблиц.

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(); 
} 

Очевидно, что вы можете использовать это в реорганизованной функции (что облегчит жизнь), но это дает вам общий вывод, который вы ищете.

+0

Конечно, это считается старым способом делать вещи - теперь, если можно, обязательно используйте DataContracts. Разница в том, что использование XMLElements позволяет все по умолчанию, тогда как Datacontracts ничего не позволяет по умолчанию. Тот же результат, просто разные способы решения проблемы. – brenton

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" } 
    }; 

Мы можем легко получить выходной XML в заданном формате с последующим Linq для запроса 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. Для того, чтобы получить XML-строка использовать String.Join<XElement> метод:

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)); 
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 Schema Definition файла (XSD) из репрезентативного файла XML ,

    В качестве альтернативы напишите несколько строк кода, чтобы прочитать 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 (например Bookings или BookingsDataSet) - а не общего назначения DataSet вы, вероятно, используете.

    Вы можете использовать xsd.exe «s /d[ataset] варианта с файлом XSD с шага 3, или вы можете добавить новый DataSet элемент для вашего проекта в Visual Studio, а затем вставьте шаг 3 производную схему в свой файл .xsd.

    То же самое - достаточно быстро в любом случае.

  4. Повторяйте по мере необходимости, пока не получите точные результаты, которые вы хотите.

авторитетный источник, MSDN имеет a good overview of XML in ADO.NET, что объясняет многое из того, что я описал.


Смежные вопросы