我正在尝试从在线购物车中获取包含多个订单的XML文件,解析它并使用C#和Visual Studio 2008将每个订单的值输出为其自己的文本文件(而不是XML)。我尝试过各种各样的此时的方法,但没有运气。我最后一次尝试包括一个绑定到XMLNodeList的foreach语句,并尝试使用XMLReader将每个元素值写入字符串,为名称为“Order”的每个节点执行我的翻译。 foreach似乎是不适用于当前配置的东西。
有更好的方法可以做到这一点还是我需要继续使用foreach?所有的想法都非常感谢。
class Class1
{
public static void Main()
{
StringBuilder orderid = new StringBuilder();
StringBuilder ordernumber = new StringBuilder();
StringBuilder name = new StringBuilder();
StringBuilder staddress = new StringBuilder();
StringBuilder city = new StringBuilder();
StringBuilder state = new StringBuilder();
StringBuilder zip = new StringBuilder();
StringBuilder country = new StringBuilder();
StringBuilder email = new StringBuilder();
StringBuilder partnumber = new StringBuilder();
StringBuilder quantity = new StringBuilder();
XmlDocument doc = new XmlDocument();
doc.Load(@"C:\onlinesales\neworders.xml");
XmlNode root = doc.DocumentElement;
XmlNodeList nodeList = root.SelectNodes("Order");
foreach (XmlNode order in nodeList)
{
using (XmlReader reader = XmlReader.Create("Order"))
{
reader.ReadToFollowing("OrderNumber");
ordernumber.Append(reader.ReadElementContentAsString());
reader.ReadToFollowing("OrderGUID");
orderid.Append(reader.ReadElementContentAsString());
reader.ReadToFollowing("FirstName");
name.Append(reader.ReadElementContentAsString());
reader.ReadToFollowing("Email");
email.Append(reader.ReadElementContentAsString());
reader.ReadToFollowing("BillingAddress1");
staddress.Append(reader.ReadElementContentAsString());
reader.ReadToFollowing("BillingCity");
city.Append(reader.ReadElementContentAsString());
reader.ReadToFollowing("BillingState");
state.Append(reader.ReadElementContentAsString());
reader.ReadToFollowing("BillingZip");
zip.Append(reader.ReadElementContentAsString());
reader.ReadToFollowing("BillingCountry");
country.Append(reader.ReadElementContentAsString());
reader.ReadToFollowing("Quantity");
quantity.Append(reader.ReadElementContentAsString());
reader.ReadToFollowing("OrderedProductManufacturerPartNumber");
partnumber.Append(reader.ReadElementContentAsString());
}
using (StreamWriter fileout =
new StreamWriter("W:" + DateTime.Now.ToString("yyyyy-MM-dd_hh-mm-ss-ff") + ".txt", false, Encoding.ASCII))
{
fileout.WriteLine("ISA*00* *00* *ZZ*daisywebstore *12*5016361200 *" + DateTime.Now.ToString("yyMMdd") + "*1559*U*00400*000001649*0*P>~");
fileout.WriteLine("GS*PO*daisywebstore*5016361200*" + DateTime.Now.ToString("yyyyMMdd") + "*" + DateTime.Now.ToString("HHmm") + "*1649*X*004010~");
fileout.WriteLine("ST*850*13~");
fileout.WriteLine("BEG*00*SA*08272226001*" + DateTime.Now.ToString("yyyyMMdd") + "~");
fileout.WriteLine("REF*DP*089~");
fileout.WriteLine("DTM*002*20120104~");
fileout.WriteLine("N1*ST*" + name + "~");
fileout.WriteLine("N3*" + staddress + "~");
fileout.WriteLine("N4*" + city + "*" + state + "*" + zip + "~");
fileout.WriteLine("N1*RE**92*00103653341~");
fileout.WriteLine("PO1*1*6*EA*33.28*TE*IN*985880-542~");
fileout.WriteLine("PID*F*****CO2 BB PISTOL $ 5693~");
fileout.WriteLine("PO4*3*1*EA~");
fileout.WriteLine("CT*1~");
fileout.WriteLine("AMT*1*199.68~");
fileout.WriteLine("SE*16*13~");
}
}
//File.Delete(@"C:\onlinesales\neworders.xml");
}
}
}
答案 0 :(得分:3)
你可以让这个变得非常简单。面向对象编程是可行的方法。
所以说你创建一个带有XElement的Order类。我会为你写几行。
public class Order
{
XElement self;
public Order(XElement order)
{
self = order;
}
public XElement Element { get { return self; } }
public string OrderNumber
{
// if your xml looks like <Order OrderNumber="somenumber" />
get { return (string)(self.Attribute("OrderNumber") ?? (object)"some default value/null"); }
// but if it looks like: <Order><OrderNumber>somenumber</OrderNumber></Order>
// get { return (string)(self.Element("OrderNumber") ?? (object)"some default value/null"); }
}
}
您必须自己填写订单的其余部分。对于每个Order值,创建一个类似我上面的OrderNumber的属性。拥有每个Order值的属性使得访问数据变得非常简单。
因此,对于您的主要代码,您需要:
XElement file = XElement.Load(@"C:\onlinesales\neworders.xml");
Order[] orders = file.Elements("Order").Select(e => new Order(e)).ToArray();
现在您已将所有订单作为单个订单对象,请在输出到文件时从属性列表中读取数据。现在不需要将值存储在StringBuilder中,因为值在Order对象中。
foreach(Order order in orders)
{
// write order.OrderNumber etc. / do whatever you want with the orders.
}
答案 1 :(得分:0)
查克有一个很好的方法。有时,您不希望保留对要加载的模型对象中的基础xml数据结构的引用。在这种情况下,我经常使用这样的模式:
public interface IXmlReadable
{
void Clear();
void Read(XPathNavigator xmlNav);
}
public class ModelBase : IXmlReadable
{
public void Clear()
{
DoClear();
}
public void Read(XPathNavigator xmlNav)
{
DoRead(xmlNav);
}
protected virtual void DoClear()
{
throw new NotImplementedException();
}
protected virtual void DoRead(XPathNavigator xmlNav)
{
throw new NotImplementedException();
}
}
可以重载阅读以接受XmlDocument
,XmlNode
,XElement
等。
现在您可以实施特定的模型。
public sealed class Order : ModelBase
{
public Order() { }
public string OrderNumber { get; private set; }
protected override void DoClear()
{
OrderNumber = string.Empty;
}
protected override void DoRead(XPathNavigator xmlNav)
{
DoClear();
XPathNavigator node;
node = xmlNav.SelectSingleNode("OrderNumber");
if (node != null)
OrderNumber = node.InnerXml;
// implement other properties here
}
}
使用XPathDocument和XPathNavigator方法,您可以执行以下操作:
XPathDocument xml = new XPathDocument(@"C:\onlinesales\neworders.xml");
xmlNav = xml.CreateNavigator();
XPathNodeIterator iterator = xmlNav.Select("Order");
while (iterator.MoveNext())
{
Order order = new Order();
order.Read(iterator.Current);
// do something with the Order - add to list or process
}