ASP.NET:将一个XmlDocument保存到Response.OutputStream是否符合编码?

Ian*_*oyd 4 xml asp.net unicode xmldocument

我想将一个XmlDocument对象的xml发送到HTTP客户端,但我担心建议的soltuion可能不会遵守Response已设置使用的编码:

public void ProcessRequest(HttpContext context)
{
   XmlDocument doc = GetXmlToShow(context);

   context.Response.ContentType = "text/xml";
   context.Response.ContentEncoding = System.Text.Encoding.UTF8;
   context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
   context.Response.Cache.SetAllowResponseInBrowserHistory(true);

   doc.Save(context.Response.OutputStream);
Run Code Online (Sandbox Code Playgroud)

}

如果我将编码更改为其他内容,例如Unicode,该怎么办?

public void ProcessRequest(HttpContext context)
{
   XmlDocument doc = GetXmlToShow(context);

   context.Response.ContentType = "text/xml";
   context.Response.ContentEncoding = System.Text.Encoding.Unicode;
   context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
   context.Response.Cache.SetAllowResponseInBrowserHistory(true);

   doc.Save(context.Response.OutputStream);
}
Run Code Online (Sandbox Code Playgroud)

请问Response.OutputStream翻译多数民众赞成被写入到它在运行中的二进制数据,并使其Unicode的?

或者Response.ContentEncoding只是提供信息

如果ContentEncoding只是提供信息,那么以下文本字符串将返回什么内容编码?

context.Response.ContentEncoding = System.Text.Encoding.Unicode;
context.Response.Write("Hello World");

context.Response.ContentEncoding = System.Text.Encoding.UTF8;
context.Response.Write("Hello World");

context.Response.ContentEncoding = System.Text.Encoding.UTF16;
context.Response.Write("Hello World");

context.Response.ContentEncoding = System.Text.Encoding.ASCII;
context.Response.Write("Hello World");

context.Response.ContentEncoding = System.Text.Encoding.BigEndianUnicode;
context.Response.Write("Hello World");
Run Code Online (Sandbox Code Playgroud)

Ian*_*oyd 14

我找到了.

答案是否定的:XmlDocument不会尊重它写入的响应流的ContentEncoding.


更新:正确的方法

  1. 使用Response.Output,而不是 Response.OutputStream.

    两者都是流,但是OutputTextWriter.

    XmlDocument将自己保存到a时TextWriter,它将使用由...指定的编码TextWriter.该XmlDocument会自动更改任何XML声明节点,即:

    <?xml version ="1.0"encoding ="ISO-8859-1"?>

    匹配Response.Output编码设置使用的编码.

  2. Response.Output TextWriter的编码设置来自 Response.ContentEncoding值.

  3. 使用doc.Save,不是 Response.Write(doc.ToString())Response.Write(doc.InnerXml)

    希望将xml保存到字符串中,或​​者将xml填充到字符串中,并且response.Write因为:

    • 不遵循指定的编码
    • 浪费记忆

总结一下:通过保存到TextWriter:XML声明节点,XML内容和HTML响应内容编码都将匹配.

示例代码:

public class Handler : IHttpHandler, System.Web.SessionState.IRequiresSessionState 
{
    //Note: We add IRequiesSessionState so that we'll have access to context.Session object
    //Otherwise it will be null


    public void ProcessRequest(HttpContext context)
    {
        XmlDocument doc = GetXmlToShow(context); //GetXmlToShow will look for parameters from the context

        if (doc != null)
        {
            context.Response.ContentType = "text/xml"; //must be 'text/xml'
            context.Response.ContentEncoding = System.Text.Encoding.UTF8; //we'd like utf-8
            doc.Save(context.Response.Output); //doc save itself to the textwriter, using the encoding of the text-writer (which comes from response.contentEncoding)
        }

        #region Notes
        /*
         * 1. Use Response.Output, and NOT Response.OutputStream.
         *    Both are streams, but Output is a TextWriter.
         *    When an XmlDocument saves itself to a TextWriter, it will use the encoding
         *    specified by the TextWriter. The XmlDocument will automatically change any
         *    xml declaration node, i.e.:
         *       <?xml version="1.0" encoding="ISO-8859-1"?>
         *    to match the encoding used by the Response.Output's encoding setting
         * 2. The Response.Output TextWriter's encoding settings comes from the 
         *    Response.ContentEncoding value.
         * 3. Use doc.Save, not Response.Write(doc.ToString()) or Response.Write(doc.InnerXml)
         * 3. You DON'T want to Save the xml to a string, or stuff the xml into a string
         *    and response.Write that, because that
         *     - doesn't follow the encoding specified
         *     - wastes memory
         * 
         * To sum up: by Saving to a TextWriter: the XML Declaration node, the XML contents,
         * and the HTML Response content-encoding will all match.
         */
        #endregion Notes
    }

    public bool IsReusable { get { return false; } }
}
Run Code Online (Sandbox Code Playgroud)

保存到流时XmlDocument将使用的编码取决于xml声明节点中指定的编码.例如:

     <?xml version="1.0" encoding="UTF-8"?>
Run Code Online (Sandbox Code Playgroud)

如果在xml声明中指定了"UTF-8"编码,则Save(stream)将使用UTF-8编码.

如果指定编码,例如:

<?xml version="1.0"?>
Run Code Online (Sandbox Code Playgroud)

或者完全省略xml声明节点,然后XmlDocument将默认为UTF-8 unicode编码.(参考)

如果未包含编码属性,则在写入或保存文档时假定为UTF-8编码.

您可以在xml声明中使用的一些常见编码字符串是:

  • UTF-8
  • UTF-16
  • ISO-10646-UCS-2
  • ISO-10646-UCS-4
  • ISO-8859-1
  • ISO-8859-2
  • ISO-8859-3
  • ISO-8859-4
  • ISO-8859-5
  • ISO-8859-6
  • ISO-8859-7
  • ISO-8859-8
  • ISO-8859-9
  • ISO-2022-JP
  • SHIFT_JIS
  • EUC-JP

注意:encoding属性不区分大小写:

与大多数XML属性不同,编码属性值不区分大小写.这是因为编码字符名称遵循ISO和Internet Assigned Numbers Authority(IANA)标准.

如果从字符串或文件加载XML,并且它不包含xml声明节点,则可以使用以下命令手动将其添加到XmlDocument:

// Create an XML declaration. 
XmlDeclaration xmldecl;
xmldecl = doc.CreateXmlDeclaration("1.0", null, null);
xmldecl.Encoding="UTF-8";

// Add the new node to the document.
XmlElement root = doc.DocumentElement;
doc.InsertBefore(xmldecl, root);
Run Code Online (Sandbox Code Playgroud)

如果XmlDocument没有xml声明,或者xml声明没有encoding属性,则保存的文档也没有.

注意:如果XmlDocument正在保存到TextWriter,那么将使用的编码将从TextWriter对象中获取.此外,当内容写入TextWriter时,xml声明节点编码属性(如果存在)将替换为TextWriter的编码.(参考)

TextWriter上的编码确定写出的编码(XmlDeclaration节点的编码由TextWriter的编码替换).如果TextWriter上未指定编码,则保存XmlDocument而不使用编码属性.

如果保存为字符串,则使用的编码由xml声明节点的编码属性(如果存在)确定.


在我的具体示例中,我通过ASP.NET写回Http客户端.我想将Response.Encoding类型设置为适当的值 - 我需要匹配XML本身将包含的内容.

执行此操作的适当方法是将xml保存到Response.Output,而不是Response.OutputStream.Response.Output是一个TextWriter,其Encoding值遵循您为Response.Encoding设置的值.

换一种说法:

context.Response.ContentEncoding = System.Text.Encoding.ASCII;
doc.Save(context.Response.Output);
Run Code Online (Sandbox Code Playgroud)

结果为xml:

<?xml version="1.0" encoding="us-ascii" ?> 
<foo>Hello, world!</foo>
Run Code Online (Sandbox Code Playgroud)

而:

context.Response.ContentEncoding = System.Text.Encoding.UTF8;
doc.Save(context.Response.Output);
Run Code Online (Sandbox Code Playgroud)

结果为xml:

<?xml version="1.0" encoding="utf-8" ?> 
<foo>Hello, world!</foo>
Run Code Online (Sandbox Code Playgroud)

context.Response.ContentEncoding = System.Text.Encoding.Unicode;
doc.Save(context.Response.Output);
Run Code Online (Sandbox Code Playgroud)

结果为xml:

<?xml version="1.0" encoding="utf-16" ?> 
<foo>Hello, world!</foo>
Run Code Online (Sandbox Code Playgroud)