character set,character encoding和xml encoding declaration

博客介绍了字符集和字符编码的概念,指出字符集是字符与数字的映射表,字符编码定义数字的字节表示,一个字符集可有多种编码。还阐述了XML编码声明,当无外部编码信息时,XML文档可用声明指定编码,通过对声明位置和内容的限制可实现自动检测。

character set,character encoding和xml encoding declaration

hanlray@gmail.com

Revision: 1.0 Date: 2005/08/31


1. character set和character encoding

一直以为character set和character encoding是一回事,最近才发现它们差不多是两个概念。从字面意思上看,一个character set就是一些字符的集合,比如26个英文字母,全体汉字,或者两者的组合,然而计算机是只能处理数字的,一个字符必须被表示成一个数字才可能被计算机处理,因此一个character set还必须定义字符到数字的映射关系,比如字符A映射到数字64,字符Z映射到数字90,这些数字叫做code points;character encoding则用来定义这些code points如何用字节表示出来,比如code point 90可以被编码为一个单字节,一个little-endian的unsigned short,一个big-endian的integer,或者更复杂的形式。换句话说,一个character set仅仅是一张字符和数字的映射表,它并不规定这些数字如何用字节表示出来,这种表示的事情由character encoding来定义。因此,一个character encoding是针对一个character set的,而一个character set可以有多个character encoding,比如UTF-8,UTF-16都是Unicode Character Set的encoding。

2. xml encoding declaration

对一段编码后的文本,要想正确地处理它,必须要事先知道其采用的编码方式,因此这种编码信息一般是存在于该文本之外的,比如某些编辑器会在文件开始放几个不可见的字节来指示其正文的编码方式,这些字节叫做BOM(Byte Order Mark);某些网络协议会有一些字段来指示其所携带文本的编码方式。这种方式很直观,很多系统/技术采用这种方式,大多数有关xml的应用也会优先使用这种外部的编码信息,但是当没有这种外部的编码信息可用的时候呢?一个xml document可以用一个xml declaration来声明其采用的编码,形如<?xml version="1.0" encoding="UTF-8"?>,这种方式看起来不大可能工作,因为这个声明本身就是文本的,并且该声明是xml document的一部分,不可能规定其采用的编码方式。如何能在不知道xml document编码的情况下理解其xml declaration中声明的编码呢?对xml编码声明的位置及内容的限制使自动检测成为可能:编码声明必须出现在文档开头,只允许ASCII字符并且其头几个字符必须是<?xml,这样,一个xml processor就可以先读出文档的前几个字节,推断其采用的编码的特征,然后用一种可以正确解码xml declaration的编码读出encoding属性值,若其值不同于解码xml declaration时的编码,则切换为该值对xml document进行处理。比如,如果前4个字节的内容为3C 3F 78 6D,则可以确定该文档采用的是一种兼容ASCII的编码,这样xml processor就可以用任一种兼容ASCII的编码(如UTF-8)来理解编码后xml声明,因为其只包含ASCII字符,任何兼容ASCII的编码对其编码的结果都是相同的。当得到xml declaration中声明的编码时,xml processor再转换到该编码对该xml进行处理。下表来自XML W3C Recommendation,列出了自动检测编码的方式:

00 00 00 3CUCS-4 or other encoding with a 32-bit code unit and ASCII characters encoded as ASCII values, in respectively big-endian (1234), little-endian (4321) and two unusual byte orders (2143 and 3412). The encoding declaration must be read to determine which of UCS-4 or other supported 32-bit encodings applies.
3C 00 00 00
00 00 3C 00
00 3C 00 00
00 3C 00 3FUTF-16BE or big-endian ISO-10646-UCS-2 or other encoding with a 16-bit code unit in big-endian order and ASCII characters encoded as ASCII values (the encoding declaration must be read to determine which)
3C 00 3F 00UTF-16LE or little-endian ISO-10646-UCS-2 or other encoding with a 16-bit code unit in little-endian order and ASCII characters encoded as ASCII values (the encoding declaration must be read to determine which)
3C 3F 78 6DUTF-8, ISO 646, ASCII, some part of ISO 8859, Shift-JIS, EUC, or any other 7-bit, 8-bit, or mixed-width encoding which ensures that the characters of ASCII have their normal positions, width, and values; the actual encoding declaration must be read to detect which of these applies, but since all of these encodings use the same bit patterns for the relevant ASCII characters, the encoding declaration itself may be read reliably
4C 6F A7 94EBCDIC (in some flavor; the full encoding declaration must be read to tell which code page is in use)
OtherUTF-8 without an encoding declaration, or else the data stream is mislabeled (lacking a required encoding declaration), corrupt, fragmentary, or enclosed in a wrapper of some kind

以下是一个简单的示例代码,涉及到前台页面、后台Java文件以及XML文件的交互: 前台页面(假设为HTML): ``` <!DOCTYPE html> <html> <head> <title>专家咨询</title> </head> <body> <form action="consultation.jsp" method="post"> <label for="text">请输入您的问题:</label><br> <textarea id="text" name="text" rows="4" cols="50"></textarea><br> <label for="field">请选择专家领域:</label><br> <select id="field" name="field"> <option value="medicine">医学</option> <option value="law">法律</option> <option value="finance">金融</option> </select><br> <input type="submit" value="提交"> </form> </body> </html> ``` 后台Java文件(假设为consultation.jsp): ```java <%@ page import="java.io.*, java.util.*" %> <%@ page import="javax.servlet.*, javax.servlet.http.*" %> <%@ page import="org.apache.commons.fileupload.*" %> <%@ page import="org.apache.commons.fileupload.disk.*" %> <%@ page import="org.apache.commons.fileupload.servlet.*" %> <%@ page import="org.apache.commons.io.output.*" %> <% // 从前台获取用户输入的问题专家领域 String text = request.getParameter("text"); String field = request.getParameter("field"); // 执行专家咨询的代码,这里只返回一个简单的字符串“hello” String result = "hello"; // 将结果返回给前台页面 response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); response.getWriter().write(result); %> ``` XML文件(假设为consultation.xml): ```xml <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fmt="http://java.sun.com/jsp/jstl/fmt" version="2.0"> <jsp:directive.page contentType="text/html;charset=UTF-8" /> <jsp:output omit-xml-declaration="yes" /> <jsp:include page="consultation.jsp" /> </jsp:root> ``` 用户界面(假设为Android的XML文件): ```xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/result_textview" android:text="等待结果..." android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/submit_button" android:text="提交" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> ``` 在Android的Java代码中,可以通过以下方式获取用户输入的问题专家领域,并将其传递给后台Java文件: ```java // 获取用户输入的问题专家领域 String text = ((EditText) findViewById(R.id.text_edittext)).getText().toString(); String field = ((Spinner) findViewById(R.id.field_spinner)).getSelectedItem().toString(); // 将问题领域上传到后台 String result = ""; try { URL url = new URL("http://example.com/consultation.xml"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setDoOutput(true); OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream()); writer.write("text=" + URLEncoder.encode(text, "UTF-8") + "&field=" + URLEncoder.encode(field, "UTF-8")); writer.flush(); BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while ((line = reader.readLine()) != null) { result += line; } writer.close(); reader.close(); } catch (Exception e) { e.printStackTrace(); } // 将结果显示在用户界面上 ((TextView) findViewById(R.id.result_textview)).setText(result); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值