我想通过数据创建XML,并且我从DataSet
或IList<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吗?
答案 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元素,因此如果您在表中添加或删除某些列不应该分解,那么应该具有固定列名称的唯一列是ID
(Booking
)和BookingID
(BookingDetail
),因为它们用于链接两个表。
答案 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 structure和Build XML Dynamically using c#
答案 5 :(得分:1)
对于迟到的回答来回答我对您的问题的评论,@ Umair Noor。
由于您使用的是.NET DataSet
,因此这是我所知道的最简单的方法,可以从中获取所需的XML - 以及相关的在线参考:
创建一个表示您希望查看的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 -->
使用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
}
这两种方法都足够快。
使用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
的{{1}}选项与步骤3中的XSD文件一起使用,或者您可以在Visual Studio中向项目添加新的/d[ataset]
项,然后粘贴该步骤-3-derived模式到其DataSet
文件中。
相同 - 两种方式都足够快。
根据需要重复,直到获得所需的确切结果。
对于权威参考,MSDN有a good overview of XML in ADO.NET解释了我所描述的大部分内容。