0

我使用 XML 作为数据库文件开发了一个 WPF 应用程序。昨天,该程序停止工作。经过一番检查,我发现Transaction.xml文件有问题。我尝试在 IE 中打开相同的内容,但出现此错误

XML 页面无法显示

无法使用样式表查看 XML 输入。请更正错误,然后单击“刷新”按钮,或稍后重试。


在文本内容中发现无效字符。错误处理资源'file:///C:/RegisterMaintenance/Transaction.xml

然后,我尝试在记事本中打开文件,它显示了奇怪的字符(下面的屏幕截图)。

在此处输入图像描述

最后,它显示了正确的xml结构。请告诉我出了什么问题以及为什么 xml 没有正确显示。怎样才能恢复到正常状态。我真的很担心,因为这是我唯一的数据文件。任何帮助或建议都会很棒。

编辑此文件的代码之一,还有其他类似类型的代码文件使用Transaction.xml

public string Add()
    {
        XDocument doc1 = XDocument.Load(@"Ledgers.xml");
        XElement elem = (from r in doc1.Descendants("Ledger")
                where r.Element("Name").Value == this.Buyer
                select r).First();
        this.TinNo = (string)elem.Element("TinNo");
        this.PhoneNo = (string)elem.Element("PhoneNo");
        this.CommissionAmount = (this.CommissionRate * this.Amount) / 100;
        this.CommissionAmount = Math.Round((decimal)this.CommissionAmount);
        this.VatAmount = (this.CommissionAmount + this.Amount) * this.VatRate / 100;
        this.VatAmount = Math.Round((decimal)this.VatAmount);
        this.InvoiceAmount = this.Amount + this.CommissionAmount + this.VatAmount;
        XDocument doc2 = XDocument.Load(@"Transactions.xml");
        var record = from r in doc2.Descendants("Transaction")
                     where (int)r.Element("Serial") == Serial
                     select r;
        foreach (XElement r in record)
        {
            r.Element("Invoice").Add(new XElement("InvoiceNo", this.InvoiceNo), new XElement("InvoiceDate", this.InvoiceDate),
                new XElement("TinNo", this.TinNo), new XElement("PhoneNo", this.PhoneNo), new XElement("TruckNo", this.TruckNo), new XElement("Source", this.Source),
                new XElement("Destination", this.Destination), new XElement("InvoiceAmount", this.InvoiceAmount),
                new XElement("CommissionRate", this.CommissionRate), new XElement("CommissionAmount", this.CommissionAmount),
                new XElement("VatRate", this.VatRate), new XElement("VatAmount", this.VatAmount));
        }
        doc2.Save(@"Transactions.xml");
        return "Invoice Created Successfully";
    }
4

2 回答 2

1

.xml 显然格式不正确。没有浏览器或其他读取 xml 文件的程序可以用它做任何事情。在几行之后xml开始正确并不重要。

所以错误肯定是它创建和/或编辑你的xml文件。你应该看看那里。也许编码是错误的。最常用的编码是 UTF-8。

另外,作为旁注,XML 并不是大型数据库的最佳格式(开销太大),因此最好切换到二进制格式。即使切换到 JSON 也会带来好处。

于 2012-07-12T07:49:01.337 回答
1

C#是一种面向对象编程(OOP) 语言,也许您应该使用一些对象!你怎么可能测试你的代码的准确性?

您应该分离出职责,例如:

public class Vat
{
    XElement self;
    public Vat(XElement parent)
    {
        self = parent.Element("Vat");
        if (null == self)
        {
            parent.Add(self = new XElement("Vat"));
            // Initialize values
            Amount = 0; 
            Rate = 0;
        }
    }

    public XElement Element { get { return self; } }

    public decimal Amount
    {
        get { return (decimal)self.Attribute("Amount"); }
        set
        {
            XAttribute a = self.Attribute("Amount");
            if (null == a)
                self.Add(new XAttribute("Amount", value));
            else
                a.Value = value.ToString();
        }
    }

    public decimal Rate
    {
        get { return (decimal)self.Attribute("Rate"); }
        set
        {
            XAttribute a = self.Attribute("Rate");
            if (null == a)
                self.Add(new XAttribute("Rate", value));
            else
                a.Value = value.ToString();
        }
    }
}

所有增值税数据将在一个节点中,所有对它的访问都将在一个可测试的类中。

你上面的 foreach 看起来更像:

foreach(XElement r in record)
{
    XElement invoice = r.Add("Invoice");
    ...
    Vat vat = new Vat(invoice);
    vat.Amount = this.VatAmount;
    vat.Rate = this.VatRate;
}

那是可读的!乍一看,从您的代码中,我什至无法判断 invoice 是否是增值税的父级,但我现在可以!

注意:这并不是说您的代码有问题,它可能是硬盘驱动器错误,因为在我看来就是这样。但是,如果您希望人们仔细阅读您的代码,请使其具有可读性和可测试性!多年后,如果您或其他人必须更改您的代码,如果它不可读,那将毫无用处。

也许从这件事中你学到了两件事

  1. 阅读能力和测试能力。
  2. 备份!(我所有有价值的 Xml 文件都在 SVN (TortoiseSVN) 中,因此我可以比较更改的内容,并保持良好的备份。SVN 已备份到在线存储。)

理想的下一步是获取属性设置器中的代码并将其重构为可测试和可重现的静态函数扩展:

public static class XAttributeExtensions
{
    public static XAttribute SetAttribute(this XElement self, string name, object value)
    {
        // test for correct arguments
        if (null == self)
            throw new ArgumentNullException("XElement to SetAttribute method cannot be null!");
        if (string.IsNullOrEmpty(name))
            throw new ArgumentNullException("Attribute name cannot be null or empty to SetAttribute method!");
        if (null == value) // how to handle?
            value = ""; // or can throw an exception like one of the above.

        // Now to the good stuff
        XAttribute a = self.Attribute(name);
        if (null == a)
            self.Add(a = new XAttribute(name, value));
        else
            a.Value = value.ToString();
        return a;
    }
}

这很容易测试,非常易读,最好的是它可以一遍又一遍地使用,得到相同的结果!

例如,可以通过以下方式大大简化 Amount 属性:

public decimal Amount
{
    get { return (decimal)self.Attribute("Amount"); }
    set { self.SetAttribute("Amount", value); }
}

我知道这是很多样板代码,但我发现它具有可读性、可扩展性和最好的可测试性。如果我想为增值税添加另一个值,我可以只修改类,而不必担心我是否在正确的位置添加了它。如果增值税有孩子,我会开设另一个增值税有财产的班级。

于 2012-07-12T20:22:24.917 回答