在从数据创建的XML结构中面临问题
本文关键字:问题 结构 XML 数据 创建 | 更新日期: 2023-09-27 17:59:14
我想通过数据创建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吗?
使用 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();
}
显然,您可以在重构函数中使用它(这将使生活更轻松(,但这为您提供了您正在寻找的一般输出。
这是一种可能的方法:
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
(,因为它们用于链接两个表。
数据对象使用 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>";
}
}
假设我们有以下数据类:
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对象的数组。要获取 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));
您可以使用 LINQ to XML 创建自定义结构。使用嵌套的 XElement 构造函数。例如,请参阅如何创建此结构的 XML 和使用 c# 动态生成 XML
很抱歉,在我对你的问题的评论之后有一个迟来的答案,@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
命令行工具从代表性 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
的/d[ataset]
选项与步骤 3 中的 XSD 文件一起使用,也可以将新的DataSet
项添加到 Visual Studio 中的项目中,然后将步骤 3 派生的架构粘贴到其.xsd
文件中。相同 - 无论哪种方式都足够快。
-
根据需要重复,直到获得所需的确切结果。
为了获得权威参考,MSDN 在 ADO.NET 中对 XML 有一个很好的概述,它解释了我所描述的大部分内容。