0

XMLをデータベースファイルとして使用してWPFアプリケーションを開発しました。昨日、プログラムは動作を停止しました。確認したところ、 Transaction.xmlファイルに問題があることがわかりました。IEで同じものを開こうとしましたが、このエラーが発生しました

XMLページを表示できません

スタイルシートを使用してXML入力を表示することはできません。エラーを修正してから[更新]ボタンをクリックするか、後でもう一度やり直してください。


テキストコンテンツに無効な文字が見つかりました。リソースの処理中にエラーが発生しました'file:/// C:/RegisterMaintenance/Transaction.xml

次に、メモ帳でファイルを開こうとすると、奇妙な文字が表示されました(下のスクリーンショット)。

ここに画像の説明を入力してください

結局、xmlの正しい構造を表示します。何がうまくいかなかったのか、なぜxmlが正しく表示されないのかを教えてください。どうすれば正常な状態に戻すことができますか。これが私の唯一のデータファイルなので、私は本当に心配しています。どんな助けや提案も素晴らしいでしょう。

このファイルを編集するコードの1つであり、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();
        }
    }
}

すべてのVatデータは1つのノードにあり、そのデータへのすべてのアクセスは1つのテスト可能なクラスにあります。

上記のforeachは次のようになります。

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

それは読みやすいです!一見すると、あなたのコードからは、請求書が付加価値税の親であるかどうかさえわかりませんが、今はわかります!

注:これは、コードに問題があると言っているのではなく、ハードドライブのエラーである可能性があります。しかし、人々にあなたのコードを熟読させたいのなら、それを読みやすく、テスト可能にしてください!数年後、あなたや他の誰かがあなたのコードを変更しなければならない場合、それが読めない場合、それは役に立たない。

おそらくこの事件からあなたは2つのことを学びました

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

これは多くの定型コードであることは知っていますが、読みやすく、拡張可能で、何よりもテスト可能であることがわかりました。Vatに別の値を追加したい場合は、クラスを変更するだけで、適切な場所に追加したかどうかを心配する必要はありません。バットに子供がいたら、私はバットがプロパティを持っていた別のクラスを作ります。

于 2012-07-12T20:22:24.917 に答える