38

XmlDocument を作成する関数があります。

public string CreateOutputXmlString(ICollection<Field> fields)
{
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Indent = true;
    settings.Encoding = Encoding.GetEncoding("windows-1250");

    StringBuilder builder = new StringBuilder();
    XmlWriter writer = XmlWriter.Create(builder, settings);

    writer.WriteStartDocument();
    writer.WriteStartElement("data");
    foreach (Field field in fields)
    {
        writer.WriteStartElement("item");
        writer.WriteAttributeString("name", field.Id);
        writer.WriteAttributeString("value", field.Value);
        writer.WriteEndElement();
    }
    writer.WriteEndElement();
    writer.Flush();
    writer.Close();

    return builder.ToString();
}

エンコーディングを設定しましたが、XmlWriter を作成した後、utf-16 エンコーディングが含まれています。文字列(およびStringBuilderと思われる)がutf-16でエンコードされており、変更できないためです。
それでは、encoding 属性を「windows-1250」に設定して、この xml を簡単に作成するにはどうすればよいでしょうか。このエンコーディングでエンコードする必要さえありません。指定された属性が必要です。

編集: .Net 2.0 である必要があるため、新しいフレームワーク要素は使用できません。

4

5 に答える 5

80

適切なエンコーディングで StringWriter を使用する必要があります。残念ながら、StringWriter ではエンコーディングを直接指定できないため、次のようなクラスが必要です。

public sealed class StringWriterWithEncoding : StringWriter
{
    private readonly Encoding encoding;

    public StringWriterWithEncoding (Encoding encoding)
    {
        this.encoding = encoding;
    }

    public override Encoding Encoding
    {
        get { return encoding; }
    }
}

(この質問は似ていますが、まったく重複していません。)

編集: コメントに答えるには: StringWriterWithEncoding をStringBuilder の代わりにXmlWriter.Createに渡し、最後に ToString() を呼び出します。

于 2009-01-09T11:24:03.037 に答える
5

これがなぜそうなのかについての追加の説明です。

文字列は、バイトではなく、一連の文字です。文字列は、Unicode コードポイントとして格納されている文字を使用しているため、それ自体は「エンコード」されません。エンコーディングは、文字列レベルでは意味がありません。

エンコーディングは、一連のコードポイント (文字) から一連のバイト (ファイルシステムやメモリなどのバイトベースのシステムでのストレージ用) へのマッピングです。フレームワークでは、16 ビットのコードポイントをバイトベースのストレージに適合させるなど、やむを得ない理由がない限り、エンコーディングを指定できません。

したがって、XML を StringBuilder に書き込もうとすると、実際には文字の XML シーケンスを構築し、それらを一連の文字として書き込んでいるので、エンコードは実行されません。したがって、エンコーディング フィールドはありません。

エンコーディングを使用する場合、XmlWriter は Stream に書き込む必要があります。

あなたが MemoryStream で見つけた解決策については、攻撃を意図したものではありませんが、腕の周りを羽ばたき、熱風を動かしているだけです。コードポイントを「windows-1252」でエンコードし、それを解析してコードポイントに戻しています。発生する可能性がある唯一の変更は、windows-1252 で定義されていない文字が「?」に変換されることです。プロセス中のキャラクター。

私にとって、正しい解決策は次の解決策かもしれません。関数の用途に応じて、Stream をパラメーターとして関数に渡すことができます。これにより、呼び出し元は、メモリに書き込むかファイルに書き込むかを決定できます。したがって、次のように記述されます。


        public static void WriteFieldsAsXmlDocument(ICollection fields, Stream outStream)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.Encoding = Encoding.GetEncoding("windows-1250");

            using(XmlWriter writer = XmlWriter.Create(outStream, settings)) {
                writer.WriteStartDocument();
                writer.WriteStartElement("data");
                foreach (Field field in fields)
                {
                    writer.WriteStartElement("item");
                    writer.WriteAttributeString("name", field.Id);
                    writer.WriteAttributeString("value", field.Value);
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
            }
        }
于 2013-02-14T08:33:11.747 に答える
3

私は実際にMemoryStreamの問題を解決しました:

public static string CreateOutputXmlString(ICollection<Field> fields)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.Encoding = Encoding.GetEncoding("windows-1250");

            MemoryStream memStream = new MemoryStream();
            XmlWriter writer = XmlWriter.Create(memStream, settings);

            writer.WriteStartDocument();
            writer.WriteStartElement("data");
            foreach (Field field in fields)
            {
                writer.WriteStartElement("item");
                writer.WriteAttributeString("name", field.Id);
                writer.WriteAttributeString("value", field.Value);
                writer.WriteEndElement();
            }
            writer.WriteEndElement();
            writer.Flush();
            writer.Close();

            writer.Flush();
            writer.Close();

            string xml = Encoding.GetEncoding("windows-1250").GetString(memStream.ToArray());

            memStream.Close();
            memStream.Dispose();

            return xml;
        }
于 2009-01-09T11:27:58.520 に答える
0

文字列を変数に出力し、utf-16への参照をutf-8に置き換えることで解決しました(私のアプリにはUTF8エンコーディングが必要でした)。関数を使用しているので、同様のことができます。私は主に VB.net を使用していますが、C# は次のようになると思います。

return builder.ToString().Replace("utf-16", "utf-8");
于 2016-12-11T18:46:55.127 に答える