1 |
r0bertz 07/10/03 17:50:19 |
2 |
|
3 |
Added: l-awk1.xml l-awk2.xml l-awk3.xml l-redesign-1.xml |
4 |
l-redesign-2.xml l-redesign-3.xml l-redesign-4.xml |
5 |
Log: |
6 |
added the following file: |
7 |
articles/l-awk1.xml articles/l-awk2.xml articles/l-awk3.xml |
8 |
articles/l-redesign-1.xml articles/l-redesign-2.xml |
9 |
articles/l-redesign-3.xml articles/l-redesign-4.xml |
10 |
|
11 |
Revision Changes Path |
12 |
1.1 xml/htdocs/doc/zh_cn/articles/l-awk1.xml |
13 |
|
14 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-awk1.xml?rev=1.1&view=markup |
15 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-awk1.xml?rev=1.1&content-type=text/plain |
16 |
|
17 |
Index: l-awk1.xml |
18 |
=================================================================== |
19 |
<?xml version='1.0' encoding="utf-8"?> |
20 |
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd"> |
21 |
<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/doc/zh_cn/articles/l-awk1.xml,v 1.1 2007/10/03 17:50:18 r0bertz Exp $ --> |
22 |
<!-- English CVS version: 1.6 --> |
23 |
|
24 |
<guide link="/doc/zh_cn/articles/l-awk1.xml" disclaimer="articles" lang="zh_cn"> |
25 |
<title>Awk实例,第1部分</title> |
26 |
|
27 |
<author title="作者"> |
28 |
<mail link="drobbins@g.o">Daniel Robbins</mail> |
29 |
</author> |
30 |
|
31 |
<author title="译者"> |
32 |
<mail link="developerWorks@×××.com">IBM developerWorks</mail> |
33 |
</author> |
34 |
|
35 |
<author title="编辑"> |
36 |
<mail link="zm3345@×××××.com">Zhou Mi</mail> |
37 |
</author> |
38 |
|
39 |
<abstract> |
40 |
Awk是一种非常好的语言,同时有一个非常奇怪的名称。在本系列(共三篇文章)的第一篇文章中,Daniel Robbins将使您迅速掌握awk编程技巧。随着本系列的进展,将讨论更高级的主题,最后将演示一个真正的高级awk演示程序。 |
41 |
</abstract> |
42 |
|
43 |
<!-- The original version of this article was published on IBM developerWorks, |
44 |
and is property of Westtech Information Services. This document is an updated |
45 |
version of the original article, and contains various improvements made by the |
46 |
Gentoo Linux Documentation team --> |
47 |
|
48 |
<version>1.3</version> |
49 |
<date>2005-10-09</date> |
50 |
|
51 |
<chapter> |
52 |
<title>一种名称很奇特的优秀语言介绍</title> |
53 |
<section> |
54 |
<title>捍卫awk</title> |
55 |
<body> |
56 |
|
57 |
<p> |
58 |
在本系列文章中,我将使您成为精通awk的编码人员。我承认,awk并没有一个非常好听且又非常“时髦”的名字。awk的GNU版本(叫作gawk)听起来非常怪异。那些不熟悉这种语言的人可能听说过“awk”,并可能认为它是一组落伍且过时的混乱代码。它甚至会使最博学的UNIX权威陷于错乱的边缘(使他不断地发出“kill -9!”命令,就象使用咖啡机一样)。 |
59 |
</p> |
60 |
|
61 |
<p> |
62 |
的确,awk没有一个动听的名字。但它是一种很棒的语言。awk适合于文本处理和报表生成,它还有许多精心设计的特性,允许进行需要特殊技巧程序设计。与某些语言不同,awk的语法较为常见。它借鉴了某些语言的一些精华部分,如C语言、python和bash(虽然在技术上,awk比python和bash早创建)。awk是那种一旦学会了就会成为您战略编码库的主要部分的语言。 |
63 |
</p> |
64 |
|
65 |
</body> |
66 |
</section> |
67 |
<section> |
68 |
<title>第一个awk</title> |
69 |
<body> |
70 |
|
71 |
<p> |
72 |
您将会见到<path>/etc/passwd</path>文件的内容出现在眼前。现在,解释awk做了些什么。调用awk时,我们指定<path>/etc/passwd</path>作为输入文件。执行awk时,它依次对<path>/etc/passwd</path>中的每一行执行print命令。所有输出都发送到stdout,所得到的结果与与执行catting <path>/etc/passwd</path>完全相同。 |
73 |
</p> |
74 |
|
75 |
<p> |
76 |
现在,解释{ print }代码块。在awk中,花括号用于将几块代码组合到一起,这一点类似于C语言。在代码块中只有一条print命令。在awk中,如果只出现print命令,那么将打印当前行的全部内容。 |
77 |
</p> |
78 |
|
79 |
<pre caption="屏显当前行"> |
80 |
$ <i>awk '{ print $0 }' /etc/passwd</i> |
81 |
$ <i>awk '{ print "" }' /etc/passwd</i> |
82 |
</pre> |
83 |
|
84 |
<p> |
85 |
在awk中,$0变量表示整个当前行,所以print和print $0的作用完全一样。 |
86 |
</p> |
87 |
|
88 |
<pre caption="用一些文字把屏幕填满"> |
89 |
$ <i>awk '{ print "hiya" }' /etc/passwd</i> |
90 |
</pre> |
91 |
|
92 |
</body> |
93 |
</section> |
94 |
<section> |
95 |
<title>多个字段</title> |
96 |
<body> |
97 |
|
98 |
<pre caption="print $1"> |
99 |
$ <i>awk -F":" '{ print $1 $3 }' /etc/passwd</i> |
100 |
halt7 |
101 |
operator11 |
102 |
root0 |
103 |
shutdown6 |
104 |
sync5 |
105 |
bin1 |
106 |
<comment>....etc.</comment> |
107 |
</pre> |
108 |
|
109 |
<pre caption="print $1 $3"> |
110 |
$ <i>awk -F":" '{ print $1 " " $3 }' /etc/passwd</i> |
111 |
</pre> |
112 |
|
113 |
<pre caption="$1$3"> |
114 |
$ <i>awk -F":" '{ print "username: " $1 "\t\tuid:" $3 }' /etc/passwd</i> |
115 |
username: halt uid:7 |
116 |
username: operator uid:11 |
117 |
username: root uid:0 |
118 |
username: shutdown uid:6 |
119 |
username: sync uid:5 |
120 |
username: bin uid:1 |
121 |
<comment>....etc.</comment> |
122 |
</pre> |
123 |
|
124 |
</body> |
125 |
</section> |
126 |
<section> |
127 |
<title>外部脚本</title> |
128 |
<body> |
129 |
|
130 |
<pre caption="示例脚本"> |
131 |
BEGIN { FS=":" } |
132 |
{ print $1 } |
133 |
</pre> |
134 |
|
135 |
<p> |
136 |
这两个方法的差别在于如何设置字段分隔符。在这个脚本中,字段分隔符在代码自身中指定(通过设置FS变量),而在前一个示例中,通过在命令行上向awk传递-F":"选项来设置FS。通常,最好在脚本自身中设置字段分隔符,只是因为这表示您可以少输入一个命令行自变量。我们将在本文的后面详细讨论FS变量。 |
137 |
</p> |
138 |
|
139 |
</body> |
140 |
</section> |
141 |
<section> |
142 |
<title>BEGIN和END块</title> |
143 |
<body> |
144 |
|
145 |
<p> |
146 |
通常,对于每个输入行,awk都会执行每个脚本代码块一次。然而,在许多编程情况中,可能需要在awk开始处理输入文件中的文本之前执行初始化代码。对于这种情况,awk允许您定义一个BEGIN块。我们在前一个示例中使用了BEGIN块。因为awk在开始处理输入文件之前会执行BEGIN块,因此它是初始化FS(字段分隔符)变量、打印页眉或初始化其它在程序中以后会引用的全局变量的极佳位置。 |
147 |
</p> |
148 |
|
149 |
<p> |
150 |
awk还提供了另一个特殊块,叫作END块。awk在处理了输入文件中的所有行之后执行这个块。通常,END块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。 |
151 |
</p> |
152 |
|
153 |
</body> |
154 |
</section> |
155 |
<section> |
156 |
<title>正则表达式和块</title> |
157 |
<body> |
158 |
|
159 |
<pre caption="正则表达式和块"> |
160 |
/foo/ { print } |
161 |
/[0-9]+\.[0-9]*/ { print } |
162 |
</pre> |
163 |
|
164 |
</body> |
165 |
</section> |
166 |
<section> |
167 |
<title>表达式和块</title> |
168 |
<body> |
169 |
|
170 |
<pre caption="fredprint"> |
171 |
$1 == "fred" { print $3 } |
172 |
</pre> |
173 |
|
174 |
<pre caption="root"> |
175 |
$5 ~ /root/ { print $3 } |
176 |
</pre> |
177 |
|
178 |
</body> |
179 |
</section> |
180 |
<section> |
181 |
<title>条件语句</title> |
182 |
<body> |
183 |
|
184 |
<pre caption="if"> |
185 |
{ |
186 |
if ( $5 ~ /root/ ) { |
187 |
print $3 |
188 |
} |
189 |
} |
190 |
</pre> |
191 |
|
192 |
<p> |
193 |
这两个脚本的功能完全一样。第一个示例中,布尔表达式放在代码块外面。而在第二个示例中,将对每一个输入行执行代码块,而且我们使用if语句来选择执行print命令。这两个方法都可以使用,可以选择最适合脚本其它部分的一种方法。 |
194 |
</p> |
195 |
|
196 |
<pre caption="if if"> |
197 |
{ |
198 |
if ( $1 == "foo" ) { |
199 |
if ( $2 == "foo" ) { |
200 |
print "uno" |
201 |
} else { |
202 |
print "one" |
203 |
} |
204 |
} else if ($1 == "bar" ) { |
205 |
print "two" |
206 |
} else { |
207 |
print "three" |
208 |
} |
209 |
} |
210 |
</pre> |
211 |
|
212 |
<pre caption="if"> |
213 |
! /matchme/ { print $1 $3 $4 } |
214 |
</pre> |
215 |
|
216 |
<pre caption="if"> |
217 |
{ |
218 |
if ( $0 !~ /matchme/ ) { |
219 |
print $1 $3 $4 |
220 |
} |
221 |
} |
222 |
</pre> |
223 |
|
224 |
<p> |
225 |
这两个脚本都只输出不包含matchme字符序列的那些行。此外,还可以选择最适合您的代码的方法。它们的功能完全相同。 |
226 |
</p> |
227 |
|
228 |
<pre caption="打印字段等于foo且等于bar的行"> |
229 |
( $1 == "foo" ) && ( $2 == "bar" ) { print } |
230 |
</pre> |
231 |
|
232 |
<p> |
233 |
这个示例只打印第一个字段等于foo且第二个字段等于bar的那些行。 |
234 |
</p> |
235 |
|
236 |
</body> |
237 |
</section> |
238 |
<section> |
239 |
<title>数值变量!</title> |
240 |
<body> |
241 |
|
242 |
<p> |
243 |
在BEGIN块中,将整数变量x初始化成零。然后,awk每次遇到空白行时,awk将执行x=x+1语句,递增x。处理完所有行之后,执行END块,awk将打印出最终摘要,指出它找到的空白行数量。 |
244 |
</p> |
245 |
|
246 |
</body> |
247 |
</section> |
248 |
<section> |
249 |
<title>字符串化的变量</title> |
250 |
<body> |
251 |
|
252 |
<pre caption="示例字段"> |
253 |
2.01 |
254 |
</pre> |
255 |
|
256 |
<pre caption="1.01x$( )1.01"> |
257 |
{ print ($1^2)+1 } |
258 |
</pre> |
259 |
|
260 |
<p> |
261 |
如果做一个小实验,就可以发现如果某个特定变量不包含有效数字,awk在对数学表达式求值时会将该变量当作数字零处理。 |
262 |
</p> |
263 |
|
264 |
</body> |
265 |
</section> |
266 |
<section> |
267 |
<title>众多的运算符</title> |
268 |
<body> |
269 |
|
270 |
<p> |
271 |
awk的另一个优点是它有完整的数学运算符集合。除了标准的加、减、乘、除,awk还允许使用前面演示过的指数运算符“^”、模(余数)运算符“%”和其它许多从C语言中借入的易于使用的赋值操作符。 |
272 |
</p> |
273 |
|
274 |
<p> |
275 |
这些运算符包括前后加减( i++ 、 --foo )、加/减/乘/除赋值运算符( a+=3 、 b*=2 、 c/=2.2 、 d-=6.2 )。不仅如此──我们还有易于使用的模/指数赋值运算符( a^=2 、 b%=4 )。 |
276 |
</p> |
277 |
|
278 |
</body> |
279 |
</section> |
280 |
<section> |
281 |
<title>字段分隔符</title> |
282 |
<body> |
283 |
|
284 |
<p> |
285 |
awk有它自己的特殊变量集合。其中一些允许调整awk的运行方式,而其它变量可以被读取以收集关于输入的有用信息。我们已经接触过这些特殊变量中的一个,FS。前面已经提到过,这个变量让您可以设置awk要查找的字段之间的字符序列。我们使用<path>/etc/passwd</path>作为输入时,将FS设置成":"。当这样做有问题时,我们还可以更灵活地使用FS。 |
286 |
</p> |
287 |
|
288 |
<pre caption="另一个字段分隔符"> |
289 |
FS="\t+" |
290 |
</pre> |
291 |
|
292 |
<p> |
293 |
以上示例中,我们使用特殊 "+" 规则表达式字符,它表示“一个或多个前一字符”。 |
294 |
</p> |
295 |
|
296 |
<pre caption="将FS设置成space"> |
297 |
FS="[[:space:]+]" |
298 |
</pre> |
299 |
|
300 |
<p> |
301 |
这个赋值表达式也有问题,它并非必要。为什么?因为缺省情况下,FS设置成单一空格字符,awk将这解释成表示“一个或多个空格或tab”。在这个特殊示例中,缺省FS设置恰恰是您最想要的! |
302 |
</p> |
303 |
|
304 |
<pre caption="字段分隔符示例"> |
305 |
FS="foo[0-9][0-9][0-9]" |
306 |
</pre> |
307 |
|
308 |
</body> |
309 |
</section> |
310 |
<section> |
311 |
<title>字段数量</title> |
312 |
<body> |
313 |
|
314 |
<pre caption="字段数量"> |
315 |
{ |
316 |
if ( NF > 2 ) { |
317 |
print $1 " " $2 ":" $3 |
318 |
} |
319 |
} |
320 |
</pre> |
321 |
|
322 |
</body> |
323 |
</section> |
324 |
<section> |
325 |
<title>记录号</title> |
326 |
<body> |
327 |
|
328 |
<pre caption="记录号"> |
329 |
{ |
330 |
<comment>#skip header</comment> |
331 |
if ( NR > 10 ) { |
332 |
print "ok, now for the real information!" |
333 |
} |
334 |
} |
335 |
</pre> |
336 |
|
337 |
<p> |
338 |
awk提供了适合各种用途的附加变量。我们将在以后的文章中讨论这些变量。 |
339 |
</p> |
340 |
|
341 |
<p> |
342 |
现在已经到了初次探索awk的尾声。随着本系列的开展,我将演示更高级的awk功能,我们将用一个真实的awk应用程序作为本系列的结尾。同时,如果急于学习更多知识,请参考以下列出的参考资料。 |
343 |
</p> |
344 |
|
345 |
</body> |
346 |
</section> |
347 |
</chapter> |
348 |
|
349 |
<chapter> |
350 |
<title>参考资料</title> |
351 |
<section> |
352 |
<title>实用链接</title> |
353 |
<body> |
354 |
|
355 |
<ul> |
356 |
<li> |
357 |
请阅读Daniel在developerWorks上的其他awk文章:通用线程:Awk实例,<uri link="l-awk2.xml">第2部分</uri>和<uri link="l-awk3.xml">第3部分</uri>。 |
358 |
</li> |
359 |
<li> |
360 |
如果想看好的老式书籍,O'Reilly 的<uri link="http://www.oreilly.com/catalog/sed2/">sed & awk, 2ndEdition</uri>是极佳选择。 |
361 |
</li> |
362 |
<li> |
363 |
请参考<uri link="http://www.faqs.org/faqs/computer-lang/awk/faq/">comp.lang.awk FAQ</uri>。它还包含许多附加awk链接。 |
364 |
</li> |
365 |
<li> |
366 |
Patrick Hartigan的<uri link="http://sparky.rice.edu/~hartigan/awk.html">awk tutorial</uri>还包括了实用的 awk 脚本。 |
367 |
</li> |
368 |
<li> |
369 |
<uri link="http://www.tasoft.com/tawk.html">Thompson's TAWK Compiler</uri>将awk脚本编译成快速二进制可执行文件。可用版本有Windows版、OS/2版、DOS版和UNIX版。 |
370 |
</li> |
371 |
<li> |
372 |
<uri link="http://www.gnu.org/software/gawk/manual/gawk.html">GNUAwk用户指南</uri>可用于在线参考。 |
373 |
</li> |
374 |
</ul> |
375 |
|
376 |
</body> |
377 |
</section> |
378 |
</chapter> |
379 |
|
380 |
</guide> |
381 |
|
382 |
|
383 |
|
384 |
|
385 |
1.1 xml/htdocs/doc/zh_cn/articles/l-awk2.xml |
386 |
|
387 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-awk2.xml?rev=1.1&view=markup |
388 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-awk2.xml?rev=1.1&content-type=text/plain |
389 |
|
390 |
Index: l-awk2.xml |
391 |
=================================================================== |
392 |
<?xml version='1.0' encoding="utf-8"?> |
393 |
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd"> |
394 |
<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/doc/zh_cn/articles/l-awk2.xml,v 1.1 2007/10/03 17:50:18 r0bertz Exp $ --> |
395 |
<!-- English CVS version: 1.6 --> |
396 |
|
397 |
<guide link="/doc/zh_cn/articles/l-awk2.xml" disclaimer="articles" lang="zh_cn"> |
398 |
<title>Awk实例,第2部分</title> |
399 |
|
400 |
<author title="作者"> |
401 |
<mail link="drobbins@g.o">Daniel Robbins</mail> |
402 |
</author> |
403 |
|
404 |
<author title="译者"> |
405 |
<mail link="developerWorks@×××.com">IBM developerWorks</mail> |
406 |
</author> |
407 |
|
408 |
<author title="编辑"> |
409 |
<mail link="zm3345@×××××.com">Zhou Mi</mail> |
410 |
</author> |
411 |
|
412 |
<abstract> |
413 |
在这篇awk简介的续集中,Daniel Robbins继续探索awk(一种很棒但有怪异名称的语言)。Daniel将演示如何处理多行记录、使用循环结构,以及创建并使用awk数组。阅读完本文后,您将精通许多awk的功能,而且可以编写您自己的功能强大的awk脚本。 |
414 |
</abstract> |
415 |
|
416 |
<!-- The original version of this article was published on IBM developerWorks, |
417 |
and is property of Westtech Information Services. This document is an updated |
418 |
version of the original article, and contains various improvements made by the |
419 |
Gentoo Linux Documentation team --> |
420 |
|
421 |
<version>1.4</version> |
422 |
<date>2005-10-31</date> |
423 |
|
424 |
<chapter> |
425 |
<title>记录、循环和数组</title> |
426 |
<section> |
427 |
<title>多行记录</title> |
428 |
<body> |
429 |
|
430 |
<p> |
431 |
awk是一种用于读取和处理结构化数据(如系统的<path>/etc/passwd</path>文件)的极佳工具。<path>/etc/passwd</path>是UNIX用户数据库,并且是用冒号定界的文本文件,它包含许多重要信息,包括所有现有用户帐户和用户标识,以及其它信息。在我的<uri link="/doc/zh_cn/articles/l-awk1.xml">前一篇文章</uri>中,我演示了awk如何轻松地分析这个文件。我们只须将FS(字段分隔符)变量设置成":"。 |
432 |
</p> |
433 |
|
434 |
<p> |
435 |
正确设置了FS变量之后,就可以将awk配置成分析几乎任何类型的结构化数据,只要这些数据是每行一个记录。然而,如果要分析占据多行的记录,仅仅依靠设置FS是不够的。在这些情况下,我们还需要修改RS记录分隔符变量。RS变量告诉awk当前记录什么时候结束,新记录什么时候开始。 |
436 |
</p> |
437 |
|
438 |
<p> |
439 |
譬如,让我们讨论一下如何完成处理“联邦证人保护计划”所涉及人员的地址列表的任务: |
440 |
</p> |
441 |
|
442 |
<pre caption="“联邦证人保护计划”所涉及人员的地址列表"> |
443 |
Jimmy the Weasel |
444 |
100 Pleasant Drive |
445 |
San Francisco, CA 12345 |
446 |
|
447 |
Big Tony |
448 |
200 Incognito Ave. |
449 |
Suburbia, WA 67890 |
450 |
</pre> |
451 |
|
452 |
<p> |
453 |
理论上,我们希望awk将每3行看作是一个独立的记录,而不是三个独立的记录。如果awk将地址的第一行看作是第一个字段($1),街道地址看作是第二个字段($2),城市、州和邮政编码看作是第三个字段$3,那么这个代码就会变得很简单。以下就是我们想要得到的代码: |
454 |
</p> |
455 |
|
456 |
<pre caption="从地址新建一个字段"> |
457 |
BEGIN { |
458 |
FS="\n" |
459 |
RS="" |
460 |
} |
461 |
</pre> |
462 |
|
463 |
<p> |
464 |
在上面这段代码中,将FS设置成"\n"告诉awk每个字段都占据一行。通过将RS设置成"",还会告诉awk每个地址记录都由空白行分隔。一旦awk知道是如何格式化输入的,它就可以为我们执行所有分析工作,脚本的其余部分很简单。让我们研究一个完整的脚本,它将分析这个地址列表,并将每个记录打印在一行上,用逗号分隔每个字段。 |
465 |
</p> |
466 |
|
467 |
<pre caption="完整的脚本"> |
468 |
BEGIN { |
469 |
FS="\n" |
470 |
RS="" |
471 |
} |
472 |
{ print $1 ", " $2 ", " $3 } |
473 |
</pre> |
474 |
|
475 |
|
476 |
<p> |
477 |
如果这个脚本保存为address.awk,地址数据存储在文件address.txt 中,可以通过输入"awk -f address.awk address.txt"来执行这个脚本。此代码将产生以下输出: |
478 |
</p> |
479 |
|
480 |
<pre caption="脚本输出"> |
481 |
Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345 |
482 |
Big Tony, 200 Incognito Ave., Suburbia, WA 67890 |
483 |
</pre> |
484 |
|
485 |
</body> |
486 |
</section> |
487 |
<section> |
488 |
<title>OFS和ORS</title> |
489 |
<body> |
490 |
|
491 |
<p> |
492 |
在address.awk的print语句中,可以看到awk会连接(合并)一行中彼此相邻的字符串。我们使用此功能在同一行上的三个字段之间插入一个逗号和空格(", ")。这个方法虽然有用,但比较难看。与其在字段间插入","字符串,倒不如让通过设置一个特殊awk变量OFS,让awk完成这件事。请参考下面这个代码片断。 |
493 |
</p> |
494 |
|
495 |
<pre caption="示例代码片断"> |
496 |
print "Hello", "there", "Jim!" |
497 |
</pre> |
498 |
|
499 |
<p> |
500 |
这行代码中的逗号并不是实际文字字符串的一部分。事实上,它们告诉awk,"Hello"、"there"和"Jim!"是单独的字段,并且应该在每个字符串之间打印OFS变量。缺省情况下,awk产生以下输出: |
501 |
</p> |
502 |
|
503 |
<pre caption="awk产生的输出"> |
504 |
Hello there Jim! |
505 |
</pre> |
506 |
|
507 |
<p> |
508 |
这是缺省情况下的输出结果,OFS被设置成" ",单个空格。不过,我们可以方便地重新定义OFS,这样awk将插入我们中意的字段分隔符。以下是原始address.awk程序的修订版,它使用OFS来输出那些中间的", |
509 |
"字符串: |
510 |
</p> |
511 |
|
512 |
<pre caption="重新定义OFS"> |
513 |
BEGIN { |
514 |
FS="\n" |
515 |
RS="" |
516 |
OFS=", " |
517 |
} |
518 |
{ print $1, $2, $3 } |
519 |
</pre> |
520 |
|
521 |
<p> |
522 |
awk还有一个特殊变量ORS,全称是“输出记录分隔符”。通过设置缺省为换行 ("\n") 的OFS,我们可以控制在print语句结尾自动打印的字符。缺省ORS值会使awk在新行中输出每个新的print语句。如果想使输出的间隔翻倍,可以将ORS设置成"\n\n"。或者,如果想要用单个空格分隔记录(而不换行),将ORS设置成""。 |
523 |
</p> |
524 |
|
525 |
</body> |
526 |
</section> |
527 |
<section> |
528 |
<title>将多行转换成用tab分隔的格式</title> |
529 |
<body> |
530 |
|
531 |
<p> |
532 |
假设我们编写了一个脚本,它将地址列表转换成每个记录一行,且用tab定界的格式,以便导入电子表格。使用稍加修改的address.awk之后,就可以清楚地看到这个程序只适合于三行的地址。如果awk遇到以下地址,将丢掉第四行,并且不打印该行: |
533 |
</p> |
534 |
|
535 |
<pre caption="Sample entry"> |
536 |
Cousin Vinnie |
537 |
Vinnie's Auto Shop |
538 |
300 City Alley |
539 |
Sosueme, OR 76543 |
540 |
</pre> |
541 |
|
542 |
<p> |
543 |
要处理这种情况,代码最好考虑每个字段的记录数量,并依次打印每个记录。现在,代码只打印地址的前三个字段。以下就是我们想要的一些代码: |
544 |
</p> |
545 |
|
546 |
<pre caption="改进后的代码"> |
547 |
BEGIN { |
548 |
FS="\n" |
549 |
RS="" |
550 |
ORS="" |
551 |
} |
552 |
|
553 |
{ |
554 |
x=1 |
555 |
while ( x<NF ) { |
556 |
print $x "\t" |
557 |
x++ |
558 |
} |
559 |
print $NF "\n" |
560 |
} |
561 |
</pre> |
562 |
|
563 |
<p> |
564 |
首先,将字段分隔符FS设置成"\n",将记录分隔符RS设置成"",这样awk可以象以前一样正确分析多行地址。然后,将输出记录分隔符ORS设置成"",它将使print语句在每个调用结尾不输出新行。这意味着如果希望任何文本从新的一行开始,那么需要明确写入print "\n"。 |
565 |
</p> |
566 |
|
567 |
<p> |
568 |
在主代码块中,创建了一个变量x来存储正在处理的当前字段的编号。起初,它被设置成1。然后,我们使用while循环(一种awk循环结构,等同于C语言中的while循环),对于所有记录(最后一个记录除外)重复打印记录和tab字符。最后,打印最后一个记录和换行;此外,由于将ORS设置成"",print将不输出换行。程序输出如下,这正是我们所期望的: |
569 |
</p> |
570 |
|
571 |
<pre caption="我们想要的输出。不算漂亮,但用tab定界,以便于导入电子表格"> |
572 |
Jimmy the Weasel 100 Pleasant Drive San Francisco, CA 12345 |
573 |
Big Tony 200 Incognito Ave. Suburbia, WA 67890 |
574 |
Cousin Vinnie Vinnie's Auto Shop 300 City Alley Sosueme, OR 76543 |
575 |
</pre> |
576 |
|
577 |
</body> |
578 |
</section> |
579 |
<section> |
580 |
<title>循环结构</title> |
581 |
<body> |
582 |
|
583 |
<p> |
584 |
我们已经看到了awk的while循环结构,它等同于相应的C语言while循环。awk还有"do...while"循环,它在代码块结尾处对条件求值,而不象标准while循环那样在开始处求值。它类似于其它语言中的"repeat...until"循环。以下是一个示例: |
585 |
</p> |
586 |
|
587 |
<pre caption="do...while示例"> |
588 |
{ |
589 |
count=1 |
590 |
do { |
591 |
print "I get printed at least once no matter what" |
592 |
} while ( count != 1 ) |
593 |
} |
594 |
</pre> |
595 |
|
596 |
<p> |
597 |
与一般的while循环不同,由于在代码块之后对条件求值,"do...while"循环永远都至少执行一次。换句话说,当第一次遇到普通while循环时,如果条件为假,将永远不执行该循环。 |
598 |
</p> |
599 |
|
600 |
</body> |
601 |
</section> |
602 |
<section> |
603 |
<title>for循环</title> |
604 |
<body> |
605 |
|
606 |
<p> |
607 |
awk允许创建for循环,它就象while循环,也等同于C语言的for循环: |
608 |
</p> |
609 |
|
610 |
<pre caption="循环示例"> |
611 |
for ( initial assignment; comparison; increment ) { |
612 |
code block |
613 |
} |
614 |
</pre> |
615 |
|
616 |
<p> |
617 |
以下是一个简短示例: |
618 |
</p> |
619 |
|
620 |
<pre caption="简短示例:"> |
621 |
for ( x = 1; x <= 4; x++ ) { |
622 |
print "iteration",x |
623 |
} |
624 |
</pre> |
625 |
|
626 |
<p> |
627 |
此段代码将打印: |
628 |
</p> |
629 |
|
630 |
<pre caption="上面代码的输出信息"> |
631 |
iteration 1 |
632 |
iteration 2 |
633 |
iteration 3 |
634 |
iteration 4 |
635 |
</pre> |
636 |
|
637 |
</body> |
638 |
</section> |
639 |
<section> |
640 |
<title>break和continue</title> |
641 |
<body> |
642 |
|
643 |
<p> |
644 |
此外,如同C语言一样,awk提供了break和continue语句。使用这些语句可以更好地控制awk的循环结构。以下是迫切需要break语句的代码片断: |
645 |
</p> |
646 |
|
647 |
<pre caption="break语句所需的代码片断"> |
648 |
while (1) { |
649 |
print "forever and ever..." |
650 |
} |
651 |
</pre> |
652 |
|
653 |
<p> |
654 |
while死循环1永远代表是真,这个while循环将永远运行下去。以下是一个只执行十次的循环: |
655 |
</p> |
656 |
|
657 |
<pre caption="只执行10次的循环"> |
658 |
x=1 |
659 |
while(1) { |
660 |
print "iteration",x |
661 |
if ( x == 10 ) { |
662 |
break |
663 |
} |
664 |
x++ |
665 |
} |
666 |
</pre> |
667 |
|
668 |
<p> |
669 |
这里,break语句用于“逃出”最深层的循环。"break"使循环立即终止,并继续执行循环代码块后面的语句。 |
670 |
</p> |
671 |
|
672 |
<p> |
673 |
continue语句补充了break,其作用如下: |
674 |
</p> |
675 |
|
676 |
<pre caption="补充break的continue语句"> |
677 |
x=1 |
678 |
while (1) { |
679 |
if ( x == 4 ) { |
680 |
x++ |
681 |
continue |
682 |
} |
683 |
print "iteration",x |
684 |
if ( x > 20 ) { |
685 |
break |
686 |
} |
687 |
x++ |
688 |
} |
689 |
</pre> |
690 |
|
691 |
<p> |
692 |
这段代码打印"iteration 1"到"iteration 21","iteration 4"除外。如果迭代等于4,则增加x并调用continue语句,该语句立即使awk开始执行下一个循环迭代,而不执行代码块的其余部分。如同break一样,continue语句适合各种awk迭代循环。在for循环主体中使用时,continue将使循环控制变量自动增加。以下是一个等价循环: |
693 |
</p> |
694 |
|
695 |
<pre caption="等价循环"> |
696 |
for ( x=1; x<=21; x++ ) { |
697 |
if ( x == 4 ) { |
698 |
continue |
699 |
} |
700 |
print "iteration",x |
701 |
} |
702 |
</pre> |
703 |
|
704 |
<p> |
705 |
在while循环中时,在调用continue之前没有必要增加x,因为for循环会自动增加x。 |
706 |
</p> |
707 |
|
708 |
</body> |
709 |
</section> |
710 |
<section> |
711 |
<title>数组</title> |
712 |
<body> |
713 |
|
714 |
<p> |
715 |
如果您知道awk可以使用数组,您一定会感到高兴。然而,在awk中,数组下标通常从1开始,而不是0: |
716 |
</p> |
717 |
|
718 |
<pre caption="awk数组示例"> |
719 |
myarray[1]="jim" |
720 |
myarray[2]=456 |
721 |
</pre> |
722 |
|
723 |
<p> |
724 |
当awk遇到第一个赋值语句时,它将创建myarray,并将元素myarray[1]设置成"jim"。在执行了第二个赋值语句后,数组就有两个元素了。 |
725 |
</p> |
726 |
|
727 |
<p> |
728 |
定义之后,awk有一个便利的机制来迭代数组元素,如下所示: |
729 |
</p> |
730 |
|
731 |
<pre caption="数组迭代"> |
732 |
for ( x in myarray ) { |
733 |
print myarray[x] |
734 |
} |
735 |
</pre> |
736 |
|
737 |
<p> |
738 |
这段代码将打印数组myarray中的每一个元素。当对于for使用这种特殊的"in"形式时,awk将myarray的每个现有下标依次赋值给x(循环控制变量),每次赋值以后都循环一次循环代码。虽然这是一个非常方便的awk功能,但它有一个缺点──当awk在数组下标之间轮转时,它不会依照任何特定的顺序。那就意味着我们不能知道以上代码的输出是: |
739 |
</p> |
740 |
|
741 |
<pre caption="以上代码的输出"> |
742 |
jim |
743 |
456 |
744 |
</pre> |
745 |
|
746 |
<p> |
747 |
还是 |
748 |
</p> |
749 |
|
750 |
<pre caption="上面代码的另一种输出"> |
751 |
456 |
752 |
jim |
753 |
</pre> |
754 |
|
755 |
<p> |
756 |
套用阿甘(Forrest Gump)的话来说,迭代数组内容就像一盒巧克力──您永远不知道将会得到什么。因此有必要使awk数组“字符串化”,我们现在就来研究这个问题。 |
757 |
</p> |
758 |
|
759 |
</body> |
760 |
</section> |
761 |
<section> |
762 |
<title>数组下标字符串化</title> |
763 |
<body> |
764 |
|
765 |
<p> |
766 |
在我的<uri |
767 |
link="/doc/zh_cn/articles/l-awk1.xml">前一篇文章</uri>中,我演示了awk实际上以字符串格式来存储数字值。虽然awk要执行必要的转换来完成这项工作,但它却可以使用某些看起来很奇怪的代码: |
768 |
</p> |
769 |
|
770 |
<pre caption="奇怪的代码"> |
771 |
a="1" |
772 |
b="2" |
773 |
c=a+b+3 |
774 |
</pre> |
775 |
|
776 |
<p> |
777 |
执行了这段代码后,c等于6。由于awk是“字符串化”的,添加字符串"1"和"2"在功能上并不比添加数字1和2难。这两种情况下,awk都可以成功执行运算。awk的“字符串化”性质非常可爱──您可能想要知道如果使用数组的字符串下标会发生什么情况。例如,使用以下代码: |
778 |
</p> |
779 |
|
780 |
<pre caption="示例代码"> |
781 |
myarr["1"]="Mr. Whipple" |
782 |
print myarr["1"] |
783 |
</pre> |
784 |
|
785 |
<p> |
786 |
可以预料,这段代码将打印"Mr. Whipple"。但如果去掉第二个"1"下标中的引号,情况又会怎样呢? |
787 |
</p> |
788 |
|
789 |
<pre caption="去掉引号的代码"> |
790 |
myarr["1"]="Mr. Whipple" |
791 |
print myarr[1] |
792 |
</pre> |
793 |
|
794 |
|
795 |
<p> |
796 |
猜想这个代码片断的结果比较难。awk将myarr["1"]和myarr[1]看作数组的两个独立元素,还是它们是指同一个元素?答案是它们指的是同一个元素,awk将打印"Mr. Whipple",如同第一个代码片断一样。虽然看上去可能有点怪,但awk在幕后却一直使用数组的字符串下标! |
797 |
</p> |
798 |
|
799 |
<p> |
800 |
了解了这个奇怪的真相之后,我们中的一些人可能想要执行类似于以下的古怪代码: |
801 |
</p> |
802 |
|
803 |
<pre caption="古怪的代码"> |
804 |
myarr["name"]="Mr. Whipple" |
805 |
print myarr["name"] |
806 |
</pre> |
807 |
|
808 |
<p> |
809 |
这段代码不仅不会产生错误,而且它的功能与前面的示例完全相同,也将打印"Mr. Whipple"!可以看到,awk并没有限制我们使用纯整数下标;如果我们愿意,可以使用字符串下标,而且不会产生任何问题。只要我们使用非整数数组下标,如myarr["name"],那么我们就在使用关联数组。从技术上讲,如果我们使用字符串下标,awk的后台操作并没有什么不同(因为即便使用“整数”下标,awk还是会将它看作是字符串)。但是,应该将它们称作关联数组──它听起来很酷,而且会给您的上司留下印象。字符串化下标是我们的小秘密。;) |
810 |
</p> |
811 |
|
812 |
</body> |
813 |
</section> |
814 |
<section> |
815 |
<title>数组工具</title> |
816 |
<body> |
817 |
|
818 |
<p> |
819 |
谈到数组时,awk给予我们许多灵活性。可以使用字符串下标,而且不需要连续的数字序列下标(例如,可以定义myarr[1]和myarr[1000],但不定义其它所有元素)。虽然这些都很有用,但在某些情况下,会产生混淆。幸好,awk提供了一些实用功能有助于使数组变得更易于管理。 |
820 |
</p> |
821 |
|
822 |
<p> |
823 |
首先,可以删除数组元素。如果想要删除数组fooarray的元素1 ,输入: |
824 |
</p> |
825 |
|
826 |
<pre caption="删除数组元素"> |
827 |
delete fooarray[1] |
828 |
</pre> |
829 |
|
830 |
<p> |
831 |
而且,如果想要查看是否存在某个特定数组元素,可以使用特殊的"in"布尔运算符,如下所示: |
832 |
</p> |
833 |
|
834 |
<pre caption="查看是否存在某个特定数组元素"> |
835 |
if ( 1 in fooarray ) { |
836 |
print "Ayep! It's there." |
837 |
} else { |
838 |
print "Nope! Can't find it." |
839 |
} |
840 |
</pre> |
841 |
|
842 |
</body> |
843 |
</section> |
844 |
<section> |
845 |
<title>下一篇</title> |
846 |
<body> |
847 |
|
848 |
<p> |
849 |
本文中,我们已经讨论了许多基础知识。下一篇中,我将演示如何使用awk的数学运算和字符串函数,以及如何创建您自己的函数,使您完全掌握awk知识。我还将指导您创建支票簿结算程序。那时,我会鼓励您编写自己的awk程序。请查阅以下参考资料。 |
850 |
</p> |
851 |
|
852 |
</body> |
853 |
</section> |
854 |
</chapter> |
855 |
|
856 |
<chapter> |
857 |
<title>参考资料</title> |
858 |
<section> |
859 |
<body> |
860 |
|
861 |
<ul> |
862 |
<li> |
863 |
请阅读Daniel在developerWorks上的其他awk文章:通用线程:Awk实例,<uri link="l-awk1.xml">第1部分</uri>和<uri link="l-awk3.xml">第3部分</uri>。 |
864 |
</li> |
865 |
<li> |
866 |
如果想看好的老式书籍,O'Reilly 的<uri link="http://www.oreilly.com/catalog/sed2/">sed & awk, 2ndEdition</uri>是极佳选择。 |
867 |
</li> |
868 |
<li> |
869 |
请参考<uri link="http://www.faqs.org/faqs/computer-lang/awk/faq/">comp.lang.awk FAQ</uri>。它还包含许多附加awk链接。 |
870 |
</li> |
871 |
<li> |
872 |
Patrick Hartigan的<uri link="http://sparky.rice.edu/~hartigan/awk.html">awk tutorial</uri>还包括了实用的 awk 脚本。 |
873 |
</li> |
874 |
<li> |
875 |
<uri link="http://www.tasoft.com/tawk.html">Thompson's TAWK Compiler</uri>将awk脚本编译成快速二进制可执行文件。可用版本有Windows版、OS/2版、DOS版和UNIX版。 |
876 |
</li> |
877 |
<li> |
878 |
<uri link="http://www.gnu.org/software/gawk/manual/gawk.html">GNUAwk用户指南</uri>可用于在线参考。 |
879 |
</li> |
880 |
</ul> |
881 |
|
882 |
</body> |
883 |
</section> |
884 |
</chapter> |
885 |
|
886 |
</guide> |
887 |
|
888 |
|
889 |
|
890 |
|
891 |
1.1 xml/htdocs/doc/zh_cn/articles/l-awk3.xml |
892 |
|
893 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-awk3.xml?rev=1.1&view=markup |
894 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-awk3.xml?rev=1.1&content-type=text/plain |
895 |
|
896 |
Index: l-awk3.xml |
897 |
=================================================================== |
898 |
<?xml version='1.0' encoding="utf-8"?> |
899 |
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd"> |
900 |
<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/doc/zh_cn/articles/l-awk3.xml,v 1.1 2007/10/03 17:50:18 r0bertz Exp $ --> |
901 |
<!-- English CVS version: 1.6 --> |
902 |
|
903 |
<guide link="/doc/zh_cn/articles/l-awk3.xml" disclaimer="articles" lang="zh_cn"> |
904 |
<title>Awk实例,第3部分</title> |
905 |
|
906 |
<author title="作者"> |
907 |
<mail link="drobbins@g.o">Daniel Robbins</mail> |
908 |
</author> |
909 |
|
910 |
<author title="译者"> |
911 |
<mail link="developerWorks@×××.com">IBM developerWorks</mail> |
912 |
</author> |
913 |
|
914 |
<author title="编辑"> |
915 |
<mail link="zm3345@×××××.com">Zhou Mi</mail> |
916 |
</author> |
917 |
|
918 |
<abstract> |
919 |
在这篇awk系列的总结中,Daniel向您介绍awk重要的字符串函数,以及演示了如何从头开始编写完整的支票簿结算程序。在这个过程中,您将学习如何编写自己的函数,并使用awk的多维数组。学完本文之后,您将掌握更多awk经验,可以让您创建功能更强大的脚本。 |
920 |
</abstract> |
921 |
|
922 |
<!-- The original version of this article was published on IBM developerWorks, |
923 |
and is property of Westtech Information Services. This document is an updated |
924 |
version of the original article, and contains various improvements made by the |
925 |
Gentoo Linux Documentation team --> |
926 |
|
927 |
<version>1.4</version> |
928 |
<date>2005-10-31</date> |
929 |
|
930 |
<chapter> |
931 |
<title>字符串函数和……支票簿?</title> |
932 |
<section> |
933 |
<title>格式化输出</title> |
934 |
<body> |
935 |
|
936 |
<p> |
937 |
虽然大多数情况下awk的print语句可以完成任务,但有时我们还需要更多。在那些情况下,awk提供了两个我们熟知的老朋友printf()和sprintf()。是的,如同其它许多awk部件一样,这些函数等同于相应的C语言函数。printf()会将格式化字符串打印到stdout,而sprintf()则返回可以赋值给变量的格式化字符串。如果不熟悉printf()和sprintf(),介绍C语言的文章可以让您迅速了解这两个基本打印函数。在Linux系统上,可以输入"man 3 printf"来查看printf()帮助页面。 |
938 |
</p> |
939 |
|
940 |
<p> |
941 |
以下是一些awk sprintf()和printf()的样本代码。可以看到,它们几乎与C语言完全相同。 |
942 |
</p> |
943 |
|
944 |
<pre caption="awk sprintf()和printf()样本代码"> |
945 |
x=1 |
946 |
b="foo" |
947 |
printf("%s got a %d on the last test\n","Jim",83) |
948 |
myout=("%s-%d",b,x) |
949 |
print myout |
950 |
</pre> |
951 |
|
952 |
<p> |
953 |
此代码将打印: |
954 |
</p> |
955 |
|
956 |
<pre caption="代码输出"> |
957 |
Jim got a 83 on the last test |
958 |
foo-1 |
959 |
</pre> |
960 |
|
961 |
</body> |
962 |
</section> |
963 |
<section> |
964 |
<title>字符串函数</title> |
965 |
<body> |
966 |
|
967 |
<p> |
968 |
awk有许多字符串函数,这是件好事。在awk中,确实需要字符串函数,因为不能象在其它语言(如C、C++和Python)中那样将字符串看作是字符数组。例如,如果执行以下代码: |
969 |
</p> |
970 |
|
971 |
<pre caption="代码示例"> |
972 |
mystring="How are you doing today?" |
973 |
print mystring[3] |
974 |
</pre> |
975 |
|
976 |
<p> |
977 |
将会接收到一个错误,如下所示: |
978 |
</p> |
979 |
|
980 |
<pre caption="代码错误信息"> |
981 |
awk: string.gawk:59: fatal: attempt to use scalar as array |
982 |
</pre> |
983 |
|
984 |
<p> |
985 |
噢,好吧。虽然不象Python的序列类型那样方便,但awk的字符串函数还是可以完成任务。让我们来看一下。 |
986 |
</p> |
987 |
|
988 |
<p> |
989 |
首先,有一个基本length()函数,它返回字符串的长度。以下是它的使用方法: |
990 |
</p> |
991 |
|
992 |
<pre caption="length()函数示例"> |
993 |
print length(mystring) |
994 |
</pre> |
995 |
|
996 |
<p> |
997 |
此代码将打印值: |
998 |
</p> |
999 |
|
1000 |
<pre caption="打印值"> |
1001 |
24 |
1002 |
</pre> |
1003 |
|
1004 |
<p> |
1005 |
好,继续。下一个字符串函数叫作index,它将返回子字符串在另一个字符串中出现的位置,如果没有找到该字符串则返回0。使用mystring,可以按以下方法调用它: |
1006 |
</p> |
1007 |
|
1008 |
<pre caption="index()函数示例"> |
1009 |
print index(mystring,"you") |
1010 |
</pre> |
1011 |
|
1012 |
<p> |
1013 |
awk会打印: |
1014 |
</p> |
1015 |
|
1016 |
<pre caption="函数输出"> |
1017 |
9 |
1018 |
</pre> |
1019 |
|
1020 |
<p> |
1021 |
让我们继续讨论另外两个简单的函数,tolower()和toupper()。与您猜想的一样,这两个函数将返回字符串并且将所有字符分别转换成小写或大写。请注意,tolower()和toupper()返回新的字符串,不会修改原来的字符串。这段代码: |
1022 |
</p> |
1023 |
|
1024 |
<pre caption="将字符转换成大写或小写"> |
1025 |
print tolower(mystring) |
1026 |
print toupper(mystring) |
1027 |
print mystring |
1028 |
</pre> |
1029 |
|
1030 |
<p> |
1031 |
……将产生以下输出: |
1032 |
</p> |
1033 |
|
1034 |
<pre caption="输出"> |
1035 |
how are you doing today? |
1036 |
HOW ARE YOU DOING TODAY? |
1037 |
How are you doing today? |
1038 |
</pre> |
1039 |
|
1040 |
<p> |
1041 |
到现在为止一切不错,但我们究竟如何从字符串中选择子串,甚至单个字符?那就是使用substr()的原因。以下是substr()的调用方法: |
1042 |
</p> |
1043 |
|
1044 |
<pre caption="substr()函数示例"> |
1045 |
mysub=substr(mystring,startpos,maxlen) |
1046 |
</pre> |
1047 |
|
1048 |
<p> |
1049 |
mystring应该是要从中抽取子串的字符串变量或文字字符串。startpos应该设置成起始字符位置,maxlen应该包含要抽取的字符串的最大长度。请注意,我说的是最大长度;如果length(mystring)比startpos+maxlen短,那么得到的结果就会被截断。substr()不会修改原始字符串,而是返回子串。以下是一个示例: |
1050 |
</p> |
1051 |
|
1052 |
<pre caption="另一个示例"> |
1053 |
print substr(mystring,9,3) |
1054 |
</pre> |
1055 |
|
1056 |
<p> |
1057 |
awk将打印: |
1058 |
</p> |
1059 |
|
1060 |
<pre caption="awk的打印结果"> |
1061 |
you |
1062 |
</pre> |
1063 |
|
1064 |
<p> |
1065 |
如果您通常用于编程的语言使用数组下标访问部分字符串(以及不使用这种语言的人),请记住substr()是awk代替方法。需要使用它来抽取单个字符和子串;因为awk是基于字符串的语言,所以会经常用到它。 |
1066 |
</p> |
1067 |
|
1068 |
<p> |
1069 |
现在,我们讨论一些更耐人寻味的函数,首先是match()。match()与index()非常相似,它与index()的区别在于它并不搜索子串,它搜索的是规则表达式。match()函数将返回匹配的起始位置,如果没有找到匹配,则返回0。此外,match()还将设置两个变量,叫作RSTART和RLENGTH。RSTART包含返回值(第一个匹配的位置),RLENGTH指定它占据的字符跨度(如果没有找到匹配,则返回-1)。通过使用RSTART、RLENGTH、substr()和一个小循环,可以轻松地迭代字符串中的每个匹配。以下是一个match()调用示例: |
1070 |
</p> |
1071 |
|
1072 |
<pre caption="match()调用示例"> |
1073 |
print match(mystring,/you/), RSTART, RLENGTH |
1074 |
</pre> |
1075 |
|
1076 |
<p> |
1077 |
awk将打印: |
1078 |
</p> |
1079 |
|
1080 |
<pre caption="上面函数的输出"> |
1081 |
9 9 3 |
1082 |
</pre> |
1083 |
|
1084 |
</body> |
1085 |
</section> |
1086 |
<section> |
1087 |
<title>字符串替换</title> |
1088 |
<body> |
1089 |
|
1090 |
<p> |
1091 |
现在,我们将研究两个字符串替换函数,sub()和gsub()。这些函数与目前已经讨论过的函数略有不同,因为它们确实修改原始字符串。以下是一个模板,显示了如何调用sub(): |
1092 |
</p> |
1093 |
|
1094 |
<pre caption="sub()函数模板"> |
1095 |
sub(regexp,replstring,mystring) |
1096 |
</pre> |
1097 |
|
1098 |
<p> |
1099 |
调用sub()时,它将在mystring中匹配regexp的第一个字符序列,并且用replstring替换该序列。sub()和gsub()用相同的自变量;唯一的区别是sub()将替换第一个regexp匹配(如果有的话),gsub()将执行全局替换,换出字符串中的所有匹配。以下是一个sub()和gsub()调用示例: |
1100 |
</p> |
1101 |
|
1102 |
<pre caption="sub()和gsub()函数调用示例"> |
1103 |
sub(/o/,"O",mystring) |
1104 |
print mystring |
1105 |
mystring="How are you doing today?" |
1106 |
gsub(/o/,"O",mystring) |
1107 |
print mystring |
1108 |
</pre> |
1109 |
|
1110 |
<p> |
1111 |
必须将mystring复位成其初始值,因为第一个sub()调用直接修改了mystring。在执行时,此代码将使awk输出: |
1112 |
</p> |
1113 |
|
1114 |
<pre caption="awk输出"> |
1115 |
HOw are you doing today? |
1116 |
HOw are yOu dOing tOday? |
1117 |
</pre> |
1118 |
|
1119 |
<p> |
1120 |
当然,也可以是更复杂的规则表达式。我把测试一些复杂规则表达式的任务留给您来完成。 |
1121 |
</p> |
1122 |
|
1123 |
<p> |
1124 |
通过介绍函数split(),我们来汇总一下已讨论过的函数。split()的任务是“切开”字符串,并将各部分放到使用整数下标的数组中。以下是一个split()调用示例: |
1125 |
</p> |
1126 |
|
1127 |
<pre caption="split()调用示例"> |
1128 |
numelements=split("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",mymonths,",") |
1129 |
</pre> |
1130 |
|
1131 |
<p> |
1132 |
调用split()时,第一个自变量包含要切开文字字符串或字符串变量。在第二个自变量中,应该指定split()将填入片段部分的数组名称。在第三个元素中,指定用于切开字符串的分隔符。split()返回时,它将返回分割的字符串元素的数量。split()将每一个片段赋值给下标从1开始的数组,因此以下代码: |
1133 |
</p> |
1134 |
|
1135 |
<pre caption="代码示例"> |
1136 |
print mymonths[1],mymonths[numelements] |
1137 |
</pre> |
1138 |
|
1139 |
<p> |
1140 |
……将打印: |
1141 |
</p> |
1142 |
|
1143 |
<pre caption="示例输出"> |
1144 |
Jan Dec |
1145 |
</pre> |
1146 |
|
1147 |
</body> |
1148 |
</section> |
1149 |
<section> |
1150 |
<title>特殊字符串形式</title> |
1151 |
<body> |
1152 |
|
1153 |
<p> |
1154 |
简短注释──调用length()、sub()或gsub()时,可以去掉最后一个自变量,这样awk将对$0(整个当前行)应用函数调用。要打印文件中每一行的长度,使用以下awk脚本: |
1155 |
</p> |
1156 |
|
1157 |
<pre caption="打印文件中每一行的长度"> |
1158 |
{ |
1159 |
print length() |
1160 |
} |
1161 |
</pre> |
1162 |
|
1163 |
</body> |
1164 |
</section> |
1165 |
<section> |
1166 |
<title>财务上的趣事</title> |
1167 |
<body> |
1168 |
|
1169 |
<p> |
1170 |
几星期前,我决定用awk编写自己的支票簿结算程序。我决定使用简单的tab定界文本文件,以便于输入最近的存款和提款记录。其思路是将这个数据交给awk脚本,该脚本会自动合计所有金额,并告诉我余额。以下是我决定如何将所有交易记录到"ASCII |
1171 |
checkbook"中: |
1172 |
</p> |
1173 |
|
1174 |
<pre caption="ASCII checkbox的交易记录"> |
1175 |
|
1176 |
23 Aug 2000 food - - Y Jimmy's Buffet 30.25 |
1177 |
</pre> |
1178 |
|
1179 |
<p> |
1180 |
此文件中的每个字段都由一个或多个tab分隔。在日期(字段1,$1)之后,有两个字段叫做“费用分类帐”和“收入分类帐”。以上面这行为例,输入费用时,我在费用字段中放入四个字母的别名,在收入字段中放入"-"(空白项)。这表示这一特定项是“食品费用”。:) 以下是存款的示例: |
1181 |
</p> |
1182 |
|
1183 |
<pre caption="存款示例"> |
1184 |
|
1185 |
23 Aug 2000 - inco - Y Boss Man 2001.00 |
1186 |
</pre> |
1187 |
|
1188 |
<p> |
1189 |
在这个实例中,我在费用分类帐中放入"-"(空白),在收入分类帐中放入"inco"。"inco"是一般(薪水之类)收入的别名。使用分类帐别名让我可以按类别生成收入和费用的明细分类帐。至于记录的其余部分,其它所有字段都是不需加以说明的。“是否付清?”字段("Y"或"N")记录了交易是否已过帐到我的帐户;除此之外,还有一个交易描述,和一个正的美元金额。 |
1190 |
</p> |
1191 |
|
1192 |
<p> |
1193 |
用于计算当前余额的算法不太难。awk只需要依次读取每一行。如果列出了费用分类帐,但没有收入分类帐(为"-"),那么这一项就是借方。如果列出了收入分类帐,但没有费用分类帐(为"-"),那么这一项就是贷方。而且,如果同时列出了费用和收入分类帐,那么这个金额就是“分类帐转帐”;即,从费用分类帐减去美元金额,并将此金额添加到收入分类帐。此外,所有这些分类帐都是虚拟的,但对于跟踪收入和支出以及预算却非常有用。 |
1194 |
</p> |
1195 |
|
1196 |
</body> |
1197 |
</section> |
1198 |
<section> |
1199 |
<title>代码</title> |
1200 |
<body> |
1201 |
|
1202 |
<p> |
1203 |
现在该研究代码了。我们将从第一行(BEGIN块和函数定义)开始: |
1204 |
</p> |
1205 |
|
1206 |
<pre caption="balance,第1部分"> |
1207 |
#!/usr/bin/env awk -f |
1208 |
BEGIN { |
1209 |
FS="\t+" |
1210 |
months="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" |
1211 |
} |
1212 |
|
1213 |
function monthdigit(mymonth) { |
1214 |
return (index(months,mymonth)+3)/4 |
1215 |
} |
1216 |
</pre> |
1217 |
|
1218 |
<p> |
1219 |
首先执行"chmod +x myscript"命令,那么将第一行"#!..."添加到任何awk脚本将使它可以直接从shell中执行。其余行定义了BEGIN块,在awk开始处理支票簿文件之前将执行这个代码块。我们将FS(字段分隔符)设置成"\t+",它会告诉awk字段由一个或多个tab分隔。另外,我们定义了字符串months,下面将出现的monthdigit()函数将使用它。 |
1220 |
</p> |
1221 |
|
1222 |
<p> |
1223 |
最后三行显示了如何定义自己的awk。格式很简单──输入"function",再输入名称,然后在括号中输入由逗号分隔的参数。在此之后,"{ |
1224 |
}"代码块包含了您希望这个函数执行的代码。所有函数都可以访问全局变量(如months变量)。另外,awk提供了"return"语句,它允许函数返回一个值,并执行类似于C和其它语言中"return"的操作。这个特定函数将以3个字母字符串格式表示的月份名称转换成等价的数值。例如,以下代码: |
1225 |
</p> |
1226 |
|
1227 |
<pre caption="monthdigit()调用示例"> |
1228 |
print monthdigit("Mar") |
1229 |
</pre> |
1230 |
|
1231 |
<p> |
1232 |
……将打印: |
1233 |
</p> |
1234 |
|
1235 |
<pre caption="monthdigit()调用示例"> |
1236 |
3 |
1237 |
</pre> |
1238 |
|
1239 |
<p> |
1240 |
现在,让我们讨论其它一些函数。 |
1241 |
</p> |
1242 |
|
1243 |
</body> |
1244 |
</section> |
1245 |
<section> |
1246 |
<title>财务函数</title> |
1247 |
<body> |
1248 |
|
1249 |
<p> |
1250 |
以下是其它三个执行簿记的函数。我们即将见到的主代码块将调用这些函数之一,按顺序处理支票簿文件的每一行,从而将相应交易记录到awk数组中。有三种基本交易,贷方(doincome)、借方(doexpense)和转帐(dotransfer)。您会发现这三个函数全都接受一个自变量,叫作mybalance。mybalance是二维数组的一个占位符,我们将它作为自变量进行传递。目前,我们还没有处理过二维数组;但是,在下面可以看到,语法非常简单。只须用逗号分隔每一维就行了。 |
1251 |
</p> |
1252 |
|
1253 |
<p> |
1254 |
我们将按以下方式将信息记录到"mybalance"中。数组的第一维从0到12,用于指定月份,0代表全年。第二维是四个字母的分类帐,如"food"或"inco";这是我们处理的真实分类帐。因此,要查找全年食品分类帐的余额,应查看mybalance[0,"food"]。要查找6月的收入,应查看mybalance[6,"inco"]。 |
1255 |
</p> |
1256 |
|
1257 |
<pre caption="查找出入信息"> |
1258 |
|
1259 |
function doincome(mybalance) { |
1260 |
mybalance[curmonth,$3] += amount |
1261 |
mybalance[0,$3] += amount |
1262 |
} |
1263 |
|
1264 |
function doexpense(mybalance) { |
1265 |
mybalance[curmonth,$2] -= amount |
1266 |
mybalance[0,$2] -= amount |
1267 |
} |
1268 |
|
1269 |
function dotransfer(mybalance) { |
1270 |
mybalance[0,$2] -= amount |
1271 |
mybalance[curmonth,$2] -= amount |
1272 |
mybalance[0,$3] += amount |
1273 |
mybalance[curmonth,$3] += amount |
1274 |
} |
1275 |
</pre> |
1276 |
|
1277 |
<p> |
1278 |
调用doincome()或任何其它函数时,我们将交易记录到两个位置──mybalance[0,category]和mybalance[curmonth, category],它们分别表示全年的分类帐余额和当月的分类帐余额。这让我们稍后可以轻松地生成年度或月度收入/支出明细分类帐。 |
1279 |
</p> |
1280 |
|
1281 |
<p> |
1282 |
如果研究这些函数,将发现在我的引用中传递了mybalance引用的数组。另外,我们还引用了几个全局变量:curmonth,它保存了当前记录所属的月份的数值,$2(费用分类帐),$3(收入分类帐)和金额($7,美元金额)。调用doincome()和其它函数时,已经为要处理的当前记录(行)正确设置了所有这些变量。 |
1283 |
</p> |
1284 |
|
1285 |
</body> |
1286 |
</section> |
1287 |
<section> |
1288 |
<title>主块</title> |
1289 |
<body> |
1290 |
|
1291 |
<p> |
1292 |
以下是主代码块,它包含了分析每一行输入数据的代码。请记住,由于正确设置了FS,可以用$1引用第一个字段,用$2引用第二个字段,依次类推。调用doincome()和其它函数时,这些函数可以从函数内部访问curmonth、$2、$3和金额的当前值。请先研究代码,在代码之后可以见到我的说明。 |
1293 |
</p> |
1294 |
|
1295 |
<pre caption="balance,第3部分"> |
1296 |
|
1297 |
{ |
1298 |
curmonth=monthdigit(substr($1,4,3)) |
1299 |
amount=$7 |
1300 |
|
1301 |
#record all the categories encountered |
1302 |
if ( $2 != "-" ) |
1303 |
globcat[$2]="yes" |
1304 |
if ( $3 != "-" ) |
1305 |
globcat[$3]="yes" |
1306 |
|
1307 |
#tally up the transaction properly |
1308 |
if ( $2 == "-" ) { |
1309 |
if ( $3 == "-" ) { |
1310 |
print "Error: inc and exp fields are both blank!" |
1311 |
exit 1 |
1312 |
} else { |
1313 |
#this is income |
1314 |
doincome(balance) |
1315 |
if ( $5 == "Y" ) |
1316 |
doincome(balance2) |
1317 |
} |
1318 |
} else if ( $3 == "-" ) { |
1319 |
#this is an expense |
1320 |
doexpense(balance) |
1321 |
if ( $5 == "Y" ) |
1322 |
doexpense(balance2) |
1323 |
} else { |
1324 |
#this is a transfer |
1325 |
dotransfer(balance) |
1326 |
if ( $5 == "Y" ) |
1327 |
dotransfer(balance2) |
1328 |
} |
1329 |
} |
1330 |
</pre> |
1331 |
|
1332 |
<p> |
1333 |
在主块中,前两行将curmonth设置成1到12之间的整数,并将金额设置成字段7(使代码易于理解)。然后,是四行有趣的代码,它们将值写到数组globcat中。globcat,或称作全局分类帐数组,用于记录在文件中遇到的所有分类帐──"inco"、"misc"、"food"、"util"等。例如,如果$2 == "inco",则将globcat["inco"]设置成"yes"。稍后,我们可以使用简单的"for (x in globcat)"循环来迭代分类帐列表。 |
1334 |
</p> |
1335 |
|
1336 |
<p> |
1337 |
在接着的大约二十行中,我们分析字段$2和$3,并适当记录交易。如果$2=="-"且$3!="-",表示我们有收入,因此调用doincome()。如果是相反的情况,则调用doexpense();如果$2和$3都包含分类帐,则调用dotransfer()。每次我们都将"balance"数组传递给这些函数,从而在这些函数中记录适当的数据。 |
1338 |
</p> |
1339 |
|
1340 |
<p> |
1341 |
您还会发现几行代码说“if ( $5 == "Y" ),那么将同一个交易记录到balance2中”。我们在这里究竟做了些什么?您将回忆起$5包含"Y"或"N",并记录交易是否已经过帐到帐户。由于仅当过帐了交易时我们才将交易记录到balance2,因此balance2包含了真实的帐户余额,而"balance"包含了所有交易,不管是否已经过帐。可以使用balance2来验证数据项(因为它应该与当前银行帐户余额匹配),可以使用"balance"来确保没有透支帐户(因为它会考虑您开出的尚未兑现的所有支票)。 |
1342 |
</p> |
1343 |
|
1344 |
</body> |
1345 |
</section> |
1346 |
<section> |
1347 |
<title>生成报表</title> |
1348 |
<body> |
1349 |
|
1350 |
<p> |
1351 |
主块重复处理了每一行记录之后,现在我们有了关于比较全面的、按分类帐和按月份划分的借方和贷方记录。现在,在这种情况下最合适的做法是只须定义生成报表的END块: |
1352 |
</p> |
1353 |
|
1354 |
<pre caption="生成最终报表"> |
1355 |
END { |
1356 |
bal=0 |
1357 |
bal2=0 |
1358 |
for (x in globcat) { |
1359 |
bal=bal+balance[0,x] |
1360 |
bal2=bal2+balance2[0,x] |
1361 |
} |
1362 |
printf("Your available funds: %10.2f\n", bal) |
1363 |
printf("Your account balance: %10.2f\n", bal2) |
1364 |
} |
1365 |
</pre> |
1366 |
|
1367 |
<p> |
1368 |
这个报表将打印出汇总,如下所示: |
1369 |
</p> |
1370 |
|
1371 |
<pre caption="最终报表"> |
1372 |
Your available funds: 1174.22 |
1373 |
Your account balance: 2399.33 |
1374 |
</pre> |
1375 |
|
1376 |
<p> |
1377 |
在END块中,我们使用"for (x in globcat)"结构来迭代每一个分类帐,根据记录在案的交易结算主要余额。实际上,我们结算两个余额,一个是可用资金,另一个是帐户余额。要执行程序并处理您在文件"mycheckbook.txt"中输入的财务数据,将以上所有代码放入文本文件"balance"执行"chmod +x balance",然后输入"./balance mycheckbook.txt"。然后balance脚本将合计所有交易,打印出两行余额汇总。 |
1378 |
</p> |
1379 |
|
1380 |
</body> |
1381 |
</section> |
1382 |
<section> |
1383 |
<title>升级</title> |
1384 |
<body> |
1385 |
|
1386 |
<p> |
1387 |
我使用这个程序的更高级版本来管理我的个人和企业财务。我的版本(由于篇幅限制不能在此涵盖)会打印出收入和费用的月度明细分类帐,包括年度总合、净收入和其它许多内容。它甚至以HTML格式输出数据,因此我可以在Web浏览器中查看它。:) 如果您认为这个程序有用,我建议您将这些特性添加到这个脚本中。不必将它配置成要记录任何附加信息;所需的全部信息已经在balance和balance2里面了。只要升级END块就万事具备了! |
1388 |
</p> |
1389 |
|
1390 |
<p> |
1391 |
我希望您喜欢本系列。有关awk的详细信息,请参考以下列出的参考资料。 |
1392 |
</p> |
1393 |
|
1394 |
</body> |
1395 |
</section> |
1396 |
</chapter> |
1397 |
|
1398 |
<chapter> |
1399 |
<title>参考资料</title> |
1400 |
<section> |
1401 |
<body> |
1402 |
|
1403 |
<ul> |
1404 |
<li> |
1405 |
请阅读Daniel在developerWorks上的其他awk文章:通用线程:Awk实例,<uri link="l-awk1.xml">第1部分</uri>和<uri link="l-awk2.xml">第2部分</uri>。 |
1406 |
</li> |
1407 |
<li> |
1408 |
如果想看好的老式书籍,O'Reilly 的<uri link="http://www.oreilly.com/catalog/sed2/">sed & awk, 2ndEdition</uri>是极佳选择。 |
1409 |
</li> |
1410 |
<li> |
1411 |
请参考<uri link="http://www.faqs.org/faqs/computer-lang/awk/faq/">comp.lang.awk FAQ</uri>。它还包含许多附加awk链接。 |
1412 |
</li> |
1413 |
<li> |
1414 |
Patrick Hartigan的<uri link="http://sparky.rice.edu/~hartigan/awk.html">awk tutorial</uri>还包括了实用的awk脚本。 |
1415 |
</li> |
1416 |
<li> |
1417 |
<uri link="http://www.tasoft.com/tawk.html">Thompson's TAWK Compiler</uri>将awk脚本编译成快速二进制可执行文件。可用版本有Windows版、OS/2版、DOS版和UNIX版。 |
1418 |
</li> |
1419 |
<li> |
1420 |
<uri link="http://www.gnu.org/software/gawk/manual/gawk.html">GNUAwk用户指南</uri>可用于在线参考。 |
1421 |
</li> |
1422 |
</ul> |
1423 |
|
1424 |
</body> |
1425 |
</section> |
1426 |
</chapter> |
1427 |
|
1428 |
</guide> |
1429 |
|
1430 |
|
1431 |
|
1432 |
1.1 xml/htdocs/doc/zh_cn/articles/l-redesign-1.xml |
1433 |
|
1434 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-redesign-1.xml?rev=1.1&view=markup |
1435 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-redesign-1.xml?rev=1.1&content-type=text/plain |
1436 |
|
1437 |
Index: l-redesign-1.xml |
1438 |
=================================================================== |
1439 |
<?xml version='1.0' encoding="utf-8"?> |
1440 |
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd"> |
1441 |
|
1442 |
<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/doc/zh_cn/articles/l-redesign-1.xml,v 1.1 2007/10/03 17:50:18 r0bertz Exp $ --> |
1443 |
<!-- English CVS version: 1.4 --> |
1444 |
|
1445 |
<guide link="/doc/zh_cn/articles/l-redesign-1.xml" disclaimer="articles" lang="zh_cn"> |
1446 |
<title>gentoo.org重新设计,第1部分:一个重生的站点</title> |
1447 |
|
1448 |
<author title="作者"> |
1449 |
<mail link="drobbins@g.o">Daniel Robbins</mail> |
1450 |
</author> |
1451 |
|
1452 |
<author title="译者"> |
1453 |
<mail link="developerWorks@×××.com">IBM developerWorks</mail> |
1454 |
</author> |
1455 |
|
1456 |
<author title="编辑"> |
1457 |
<mail link="zm3345@×××××.com">Zhou Mi</mail> |
1458 |
</author> |
1459 |
|
1460 |
<abstract> |
1461 |
您是否曾在某个清晨醒来,突然意识到自己开发的那个很酷的小网站实际上并不那么棒?如果是这样,那么您现在找对地方了。在本系列中,Daniel Robbins共享了它在使用诸如XML、XSLT和Python之类的技术重新设计www.gentoo.org网站时得到的经验。在此过程中,您也许还会发现一些优秀的方法适合于您的下一次网站重新设计。在本文中,Daniel创建了一个以用户为中心的行动计划,而且还介绍了pytext,这是一种嵌入式Python解释器。 |
1462 |
</abstract> |
1463 |
|
1464 |
<!-- The original version of this article was first published on IBM |
1465 |
developerWorks, and is property of Westtech Information Services. This |
1466 |
document is an updated version of the original article, and contains |
1467 |
various improvements made by the Gentoo Linux Documentation team --> |
1468 |
|
1469 |
<version>1.0</version> |
1470 |
<date>2005-10-10</date> |
1471 |
|
1472 |
<chapter> |
1473 |
<title>任性的人</title> |
1474 |
<section> |
1475 |
<body> |
1476 |
|
1477 |
<p> |
1478 |
软件开发人员,我能问您一个问题吗?虽然我们中有许多人都非常熟悉Web技术,如HTML、CGI、Perl、Python、Java技术和XML,但为什么我们自己的网站──那些专用于我们珍爱的开发项目的网站──却看似由一大群任性活泼的12孩子胡乱拼凑起来的呢?为什么,为什么会这样? |
1479 |
</p> |
1480 |
|
1481 |
<p> |
1482 |
难道是因为在大多数时间里,我们对自己的网站放任不管,而挥霍了宝贵的时间来修改我们的自由软件项目?答案,至少在我的个案中,是最明确的:“是的”。 |
1483 |
</p> |
1484 |
|
1485 |
<p> |
1486 |
当我不为IBM developerWorks撰写文章或刚作爸爸时,我和我那组技术高超的志愿者疯狂地投入了Gentoo Linux下一个发行版的工作中。是的,Gentoo Linux有其自己的网站(请参阅<uri link="#resources">参考资料</uri>)。目前(2001年3月),我们的网站还没那么特别;那是因为我们没有花很多时间在它上面,因为我们通常将精力都投入到改进Gentoo Linux上。的确,我们的站点有几个我用Xara X(请参阅<uri link="#resources">参考资料</uri>)很快设计出的、公认的可爱徽标,但在这赏心悦目的外观之下,我们的站点还有许多不足之处。也许您的站点也是这样。如果是这样,那么我有句话要对您说──欢迎来到俱乐部。 |
1487 |
</p> |
1488 |
|
1489 |
</body> |
1490 |
</section> |
1491 |
</chapter> |
1492 |
|
1493 |
<chapter> |
1494 |
<title>www.gentoo.org</title> |
1495 |
<section> |
1496 |
<body> |
1497 |
|
1498 |
<p> |
1499 |
在我们的案例中,由于项目在成长,而网站却没有,因而使网站陷入了进退两难的局面。现在,Gentoo Linux正准备出1.0发行版(当它可以正式向非开发人员发布时),而且日趋普及,我们需要开始认真地研究网站如何能够更好地为其用户服务。以下是www.gentoo.org的快照: |
1500 |
</p> |
1501 |
|
1502 |
<figure link="/images/docs/l-redesign-01.gif" caption="www.gentoo.org当时(2001年3月)的情形"/> |
1503 |
|
1504 |
<p> |
1505 |
可以看到,我们有了所有最基本的要素──Gentoo Linux的描述、功能部件列表、每日“更改日志”(由Python自动更新),以及许多重要链接(链接到下载站点、邮件列表注册页面和cvsWeb)。我们还有到三个文档资源的链接──Gentoo Linux安装指南和开发指南,以及Christian Zander的NVIDIA故障排除指南。 |
1506 |
</p> |
1507 |
|
1508 |
<p> |
1509 |
然而,虽然站点看起来不错,但我们遗漏了很多东西。最明显的是文档──我们的安装和开发指南需要大量工作。然后,我们需要添加FAQ、新链接、新用户信息……这个清单是没完没了的。 |
1510 |
</p> |
1511 |
|
1512 |
</body> |
1513 |
</section> |
1514 |
<section> |
1515 |
<title>内容 vs. 显示</title> |
1516 |
<body> |
1517 |
|
1518 |
<p> |
1519 |
现在,我们讨论第二个问题。目前,所有工作都以原始HTML格式完成;我不断修改index.html文件,直到它看上去让我满意为止。更糟的是,我们的Web文档都是以原始HTML格式编写的。从开发角度看,这并不是件好事,因为原始内容(包括段落、章、节)与许多与显示相关的HTML标记混合在一起。当然,这会使更改内容和站点外观变得更困难。虽然这种方法目前还有用,但在我们的站点继续成长时,它必定会引起某些问题。 |
1520 |
</p> |
1521 |
|
1522 |
<p> |
1523 |
显然,我们需要在后台使用更好的技术。我们需要使用类似于XML、XSLT和Python的东西,而不是直接使用HTML。目标是尽可能多地采用自动化,这样我们就可以轻松添加和扩充站点。如果我们很好地完成了任务,那么将来对站点的重大更改应该会相对没有痛苦。 |
1524 |
</p> |
1525 |
|
1526 |
</body> |
1527 |
</section> |
1528 |
<section> |
1529 |
<title>策略!</title> |
1530 |
<body> |
1531 |
|
1532 |
<p> |
1533 |
显然,我们还需要做大量工作。实际上,有许多工作要完成,而我却不知道从哪里开始。正当我尝试理清头绪时,无意中发现了Laura Wonnacott的“Site Savvy”InfoWorld专栏(请参阅<uri link="#resources">参考资料</uri>)。在这个专栏中,她说明了“以用户为中心”设计的概念──如何在关注目标观众(在此案例中是指Gentoo Linux用户和开发人员)需要的同时改进网站。阅读这篇文章并查看该文章中的“以用户为中心设计手册”链接(请参阅<uri link="#sources">参考资料</uri>)帮助我制订重新设计的策略──行动计划: |
1534 |
</p> |
1535 |
|
1536 |
<ol> |
1537 |
<li> |
1538 |
首先,明确定义网站的正式目标──把它“写”下来:其目的是什么?它应该做什么? |
1539 |
</li> |
1540 |
<li> |
1541 |
区分访问您网站的不同用户类型──您预期的访问者。按优先级别给他们排序:哪些人对您来说是最重要的? |
1542 |
</li> |
1543 |
<li> |
1544 |
建立一个用户反馈系统,您可以从他们那里得知做得对还是不对。 |
1545 |
</li> |
1546 |
<li> |
1547 |
分析反馈信息,并得出结论:哪些站点是需要改进和重新设计的。应该优先考虑高级用户的意见。 |
1548 |
</li> |
1549 |
<li> |
1550 |
一旦选定了站点中要整改的部分,立马去做吧!在实施期间,要确定新的内容与设计符合您目标用户的需求,并且修复了所有已知的不足。 |
1551 |
</li> |
1552 |
<li> |
1553 |
当完成了部分重新设计时,即使它看来与当前站点有着明显差别,也应将它添加到正在运转的站点。这样,您的用户可以立即开始受益于最近重新设计的部分。如果重新设计有问题,您可以更快得到用户反馈。最后,不断改进站点(而不是重建整个站点,然后突然推出它──令人吃惊!)有助于防止用户对(可能是巨大的)站点更改产生陌生感。 |
1554 |
</li> |
1555 |
<li>完成了第6步之后,跳到第4步,然后重复。</li> |
1556 |
</ol> |
1557 |
|
1558 |
</body> |
1559 |
</section> |
1560 |
<section> |
1561 |
<title>任务说明</title> |
1562 |
<body> |
1563 |
|
1564 |
<p> |
1565 |
我很高兴地发现我们已经完成了第3步。我们已经接收到了几封来自站点访问者的电子邮件建议,而我们的开发人员邮件列表也提供了一种交换建议和意见的方法。然而,我还没有真正完成步骤1和2。虽然答案也许看似明显,但我确实发现真正坐下写出任务说明很有帮助: |
1566 |
</p> |
1567 |
|
1568 |
<p> |
1569 |
www.gentoo.org是为了帮助使用和开发Gentoo Linux的人们而存在的,它提供了关于Gentoo Linux和一般Linux的最新信息,主要关注与Gentoo Linux安装、使用、管理和开发有关的主题。作为有关Gentoo所有事情的主要中心,该站点还应该提供与Gentoo Linux用户和开发人员相关的重要新闻。除了迎合Gentoo Linux用户和开发人员,www.gentoo.org还有第二个目的,那就是满足潜在Gentoo Linux用户的需要,它提供了这些用户确定Gentoo Linux是否适合他们所需的信息。 |
1570 |
</p> |
1571 |
|
1572 |
</body> |
1573 |
</section> |
1574 |
<section> |
1575 |
<title>使用人群</title> |
1576 |
<body> |
1577 |
|
1578 |
<p> |
1579 |
到目前为止,一切顺利。现在,到了第2步──明确访问对象: |
1580 |
</p> |
1581 |
|
1582 |
<p> |
1583 |
www.gentoo.org有三种访问对象──Gentoo Linux开发人员、使用者和潜在的用户。虽然没有一组肯定比另一组拥有更高的优先级,但目前Gentoo Linux开发人员的需要是我们的最高优先级,其次是Gentoo Linux用户,然后是潜在用户。这是因为Gentoo Linux当前处于预先发行状态。当Gentoo Linux达到版本1.0时,Gentoo Linux用户和潜在用户也将得到优先级。 |
1584 |
</p> |
1585 |
|
1586 |
</body> |
1587 |
</section> |
1588 |
<section> |
1589 |
<title>意见和建议</title> |
1590 |
<body> |
1591 |
|
1592 |
<p> |
1593 |
O.K.,现在该分析我们收集的建议和意见了: |
1594 |
</p> |
1595 |
|
1596 |
<p> |
1597 |
在过去的几个月中,我们收到了许多来自网站访问者的建议。绝大多数时候,人们都要求更好的文档──无论是开发人员还是用户。有一些开发人员询问我们是否可以创建一个邮件列表,它将专用于描述CVS提交。 |
1598 |
</p> |
1599 |
|
1600 |
<p> |
1601 |
有趣的是,我们还接收到一些电子邮件,询问Gentoo Linux是商业产品还是免费产品。我猜想那是因为我们的主徽标上铭刻了“Gentoo Technologies, Inc.”(我们的法定公司名称),人们认为我们有商业目的。修改徽标,以使它显示“Gentoo Linux”,并在主页面上添加小的起始段落以说明我们是自由软件项目,这样会有所帮助。 |
1602 |
</p> |
1603 |
|
1604 |
</body> |
1605 |
</section> |
1606 |
<section> |
1607 |
<title>改进列表</title> |
1608 |
<body> |
1609 |
|
1610 |
<p> |
1611 |
O.K.,现在让我们将这些建议转变成可行的改进列表: |
1612 |
</p> |
1613 |
|
1614 |
<ul> |
1615 |
<li>重建主页面 |
1616 |
<ul> |
1617 |
<li>实现:更新徽标并添加自由软件简介</li> |
1618 |
<li>目的:明确说明我们是自由软件项目</li> |
1619 |
<li>目标人群:潜在的用户</li> |
1620 |
<li>难度:中等</li> |
1621 |
</ul> |
1622 |
</li> |
1623 |
<li>改进基本用户文档 |
1624 |
<ul> |
1625 |
<li>实现:新的XML/XSLT系统,详细文档</li> |
1626 |
<li>目的:使用户安装 Gentoo Linux 更容易</li> |
1627 |
<li>目标人群:新用户</li> |
1628 |
<li>难度:中等</li> |
1629 |
</ul> |
1630 |
</li> |
1631 |
<li>改进/创建开发人员文档 |
1632 |
<ul> |
1633 |
<li>实现:新的XML/XSLT系统、CVS指南、开发系统、移植指南</li> |
1634 |
<li>目的:帮助开发人员出色地完成工作</li> |
1635 |
<li>目标人群:开发人员</li> |
1636 |
<li>难度:大</li> |
1637 |
</ul> |
1638 |
</li> |
1639 |
<li>添加CVS邮件列表 |
1640 |
<ul> |
1641 |
<li>实现:使用现有邮差邮件列表管理器</li> |
1642 |
<li>目的:更好地通知开发人员</li> |
1643 |
<li>目标人群:开发人员</li> |
1644 |
<li>难度:小</li> |
1645 |
</ul> |
1646 |
</li> |
1647 |
</ul> |
1648 |
|
1649 |
</body> |
1650 |
</section> |
1651 |
<section> |
1652 |
<title>选择!</title> |
1653 |
<body> |
1654 |
|
1655 |
<p> |
1656 |
出于不同的原因,列表中有两件事引人注意。第一件是CVS邮件列表──这件事无须费神,因为它很容易实现。通常,首先实现最简单的更改比较合理,这样用户可以立即从中获益。 |
1657 |
</p> |
1658 |
|
1659 |
<p> |
1660 |
列表中第二件值得注意的事就是开发人员文档的需要。这是一个长期项目,会需要很多工作。根据我与其他开发人员的交谈,我们都认同某种XML/XSL方法是正确的解决方案。 |
1661 |
</p> |
1662 |
|
1663 |
</body> |
1664 |
</section> |
1665 |
<section> |
1666 |
<title>XML/XSL原型</title> |
1667 |
<body> |
1668 |
|
1669 |
<p> |
1670 |
为了帮助启动过程,我开发了原型XML语法,以用于所有在线文档。通过使用这个XML语法(称作“guide”),文档将明确地组织成段落、章和节(使用类似于<section>, <chapter>等的XML标记),而同时不包含任何与显示相关的标记。为了创建在站点上显示的HTML,我创建了XSL转换的原型集合。通过使用诸如Sablotron的XSLT处理器,guide XML文件可以按以下方式转换成HTML: |
1671 |
</p> |
1672 |
|
1673 |
<pre caption="将guide XML文件转换成HTML"> |
1674 |
devguide.xml + guide.xsl ---XSLT processor---> devguide.html |
1675 |
</pre> |
1676 |
|
1677 |
<p> |
1678 |
这个XML/XSLT方法的优点是它将原始内容(XML)与guide.xsl(XSLT)文件中的与显示相关的信息隔离开。如果需要更新Web页面的外观,只需修改guide.xsl文件并通过XSLT处理器(Sablotron)运行所有XML,就能创建更新的HTML页面。或者,如果需要向开发指南添加几章,则可以修改devguide.xml。完成之后,通过Sablotron运行XML,就会生成完全格式化的devguide.html文件,其中包含了添加的几章。将XML看作是内容,将SLT看作是与显示相关的格式化宏。 |
1679 |
</p> |
1680 |
|
1681 |
<p> |
1682 |
虽然整个小组都相信XML/XSLT是正确方法,但我们对正式XML语法还没有达成一致意见。Achim,我们的开发领导,建议我们使用docbook来代替使用我们自己的XML语法。然而,原型指南XML格式已经促使我们开始了决策过程。因为我们开发人员每天都会使用XML/XSL,因此选择一个我们都感到满意且满足我们所有需要的解决方案至关重要。在下一篇文章中,我将向您演示有效的XML/XSL文档系统。 |
1683 |
</p> |
1684 |
|
1685 |
</body> |
1686 |
</section> |
1687 |
<section> |
1688 |
<title>技术演示:pytext</title> |
1689 |
<body> |
1690 |
|
1691 |
<p> |
1692 |
一般情况下,我们的当前网站不使用值得一提的任何新的或超酷的技术。然而,这里有一个例外值得注意──我们的小pytext,这是一个嵌入式Python解释器。 |
1693 |
</p> |
1694 |
|
1695 |
<p> |
1696 |
就象你们中的许多人一样,我是个超级Python爱好者,在所有脚本语言中我最喜欢它,因此当向网站添加一些动态内容时,我当然想要使用Python。您也许知道,在编码动态HTML内容时,与其它方法相比,通常将语言命令嵌入到HTML内部更为方便。因此,需要一个嵌入式Python解释器,它可以接受如下文档: |
1697 |
</p> |
1698 |
|
1699 |
<pre caption="源码文档"> |
1700 |
<p> |
1701 |
Yeah, sure; I got some questions:<br> |
1702 |
<!--code |
1703 |
names=["bob","jimmy","ralph"] |
1704 |
items=["socks","lunch","accordion"] |
1705 |
for x in items: |
1706 |
for y in names: |
1707 |
print "Anyone seen",y+"'s",x+"?<br>" |
1708 |
--> |
1709 |
See, told you so. |
1710 |
</pre> |
1711 |
|
1712 |
<p> |
1713 |
……然后将它转换成: |
1714 |
</p> |
1715 |
|
1716 |
<pre caption="目标文档"> |
1717 |
<p> |
1718 |
Yeah, sure; I got some questions:<br> |
1719 |
Anyone seen bob's socks?<br> |
1720 |
Anyone seen jimmy's socks?<br> |
1721 |
Anyone seen ralph's socks?<br> |
1722 |
Anyone seen bob's lunch?<br> |
1723 |
Anyone seen jimmy's lunch?<br> |
1724 |
Anyone seen ralph's lunch?<br> |
1725 |
Anyone seen bob's accordion?<br> |
1726 |
Anyone seen jimmy's accordion?<br> |
1727 |
Anyone seen ralph's accordion?<br> |
1728 |
See, told you so. |
1729 |
</pre> |
1730 |
|
1731 |
<p> |
1732 |
下面是pytext的源代码: |
1733 |
</p> |
1734 |
|
1735 |
<pre caption="pytext嵌入式Python解释器"> |
1736 |
#!/usr/bin/env python |
1737 |
|
1738 |
# pytext 2.1 |
1739 |
# Copyright 1999-2001 Daniel Robbins |
1740 |
# Distributed under the GPL |
1741 |
|
1742 |
import sys |
1743 |
|
1744 |
def runfile(myarg): |
1745 |
"interprets a text file with embedded elements" |
1746 |
mylocals={} |
1747 |
try: |
1748 |
a=open(myarg,'r') |
1749 |
except IOError: |
1750 |
sys.stderr.write("!!! Error opening "+myarg+"!\n") |
1751 |
return |
1752 |
mylines=a.readlines() |
1753 |
a.close() |
1754 |
pos=0 |
1755 |
while pos<len(mylines): |
1756 |
if mylines[pos][0:8]=="<!--code": |
1757 |
mycode="" |
1758 |
pos=pos+1 |
1759 |
while (pos<len(mylines)) and (mylines[pos][0:3]!="-->"): |
1760 |
mycode=mycode+mylines[pos] |
1761 |
pos=pos+1 |
1762 |
exec(mycode,globals(),mylocals) |
1763 |
else: |
1764 |
sys.stdout.write(mylines[pos]) |
1765 |
pos=pos+1 |
1766 |
|
1767 |
if len(sys.argv)>1: |
1768 |
for x in sys.argv[1:]: |
1769 |
runfile(x) |
1770 |
sys.exit(0) |
1771 |
else: |
1772 |
sys.stderr.write |
1773 |
("pytext 2.1 -- Copyright 1999-2001 Daniel Robbins. ") |
1774 |
sys.stderr.write |
1775 |
("Distributed under the\nGNU Public License\n\n") |
1776 |
sys.stderr.write |
1777 |
("Usage: "+sys.argv[0]+" file0 [file1]...\n") |
1778 |
sys.exit(1) |
1779 |
</pre> |
1780 |
|
1781 |
</body> |
1782 |
</section> |
1783 |
<section> |
1784 |
<title>pytext工作原理</title> |
1785 |
<body> |
1786 |
|
1787 |
<p> |
1788 |
这里说明它是如何工作的。它会扫描每一个输入行,而且在大多数时间里,每个输入行都只是回显到标准输出。但是,如果pytext遇到以<!--code开头的行,那么直到第一行以-->开头的每一行的内容都会被附加到称作mycode的字符串中。然后pytext使用内置exec()函数执行mycode字符串,从而有效地创建嵌入式Python解释器。 |
1789 |
</p> |
1790 |
|
1791 |
<p> |
1792 |
关于这个特殊的实现,确实有一些美妙的东西──我们以这种方式调用exec(),这样会保存对全局和本地名称空间的所有修改。这样,就可以导入模块或在某嵌入块中定义变量,然后在以后创建的块中访问这个先创建的对象,如以下示例明确演示的那样: |
1793 |
</p> |
1794 |
|
1795 |
<pre caption="示例代码"> |
1796 |
<!--code |
1797 |
import os |
1798 |
foo=23 |
1799 |
--> |
1800 |
|
1801 |
Hello |
1802 |
|
1803 |
<!--code |
1804 |
print foo |
1805 |
if os.path.exists("/tmp/mytmpfile"): |
1806 |
print "it exists" |
1807 |
else: |
1808 |
print "I don't see it" |
1809 |
--> |
1810 |
</pre> |
1811 |
|
1812 |
<p> |
1813 |
很方便,是吗?pytext服务是Python强大功能的极佳演示,并且对于Python爱好者来说是极其有用的工具。对于当前站点,我们从cron作业中调用pytext,使用它定期为主页面“更改日志”生成HTML代码: |
1814 |
</p> |
1815 |
|
1816 |
<pre caption="主页HTML代码的生成"> |
1817 |
pytext index.ehtml > index.html |
1818 |
</pre> |
1819 |
|
1820 |
<p> |
1821 |
就写到这吧;下次见面时,我会讨论www.gentoo.org重新设计的第一阶段! |
1822 |
</p> |
1823 |
|
1824 |
</body> |
1825 |
</section> |
1826 |
</chapter> |
1827 |
|
1828 |
<chapter id="resources"> |
1829 |
<title>参考资料</title> |
1830 |
<section> |
1831 |
<body> |
1832 |
|
1833 |
<ul> |
1834 |
<li> |
1835 |
请参阅用XML,XSLT和Python等技术重新设计www.gentoo.org网站系列文章的其他部分: |
1836 |
<ul> |
1837 |
<li> |
1838 |
在<uri link="/doc/zh_cn/articles/l-redesign-2.xml">第2部分</uri>中,Daniel将展示新的文档系统以及建立一个CVS-log邮件日志列表(2001年3月)。 |
1839 |
</li> |
1840 |
<li> |
1841 |
在<uri link="/doc/zh_cn/articles/l-redesign-3.xml">第3部分</uri>中,他将给网站一个新的外观(2001年7月)。 |
1842 |
</li> |
1843 |
<li> |
1844 |
在<uri link="/doc/zh_cn/articles/l-redesign-4.xml">第4部分</uri>中,Daniel完成了到XML/XSLT的转换,修复了Netscape 4.x浏览器的访问bug,还为网站添加了自动生成的XML Changelog(2001年8月)。 |
1845 |
</li> |
1846 |
</ul> |
1847 |
</li> |
1848 |
<li> |
1849 |
如果您还没有开始使用 Python,那您只是在自找麻烦。在<uri>http://www.python.org</uri>上可以找到它。 |
1850 |
</li> |
1851 |
<li> |
1852 |
Laura Wonnacott的<uri link="http://www.infoworld.com/articles/op/xml/01/03/05/010305opsavvy.xml">Site Savvy专栏</uri>会定期出现在<uri>InfoWorld.com</uri>。 |
1853 |
</li> |
1854 |
<li> |
1855 |
请查看Xara X的主页<uri link="http://www.xara.com/">Xara.com</uri>──Xara X是一款极佳的Windows下的向量绘图软件包。它几乎没有一点多余功能,却有惊人的速度,建议您使用该软件。 |
1856 |
</li> |
1857 |
<li><uri>http://www.xslt.com</uri>上可以学到关于XSLT的更多知识。</li> |
1858 |
<li> |
1859 |
弄明白之后,请查看Sablotron,这是一个又快又好的XSLT处理器,可以从<uri link="http://www-gingerall.com">Gingerall</uri>获得。 |
1860 |
</li> |
1861 |
</ul> |
1862 |
|
1863 |
</body> |
1864 |
</section> |
1865 |
</chapter> |
1866 |
</guide> |
1867 |
|
1868 |
|
1869 |
|
1870 |
1.1 xml/htdocs/doc/zh_cn/articles/l-redesign-2.xml |
1871 |
|
1872 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-redesign-2.xml?rev=1.1&view=markup |
1873 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-redesign-2.xml?rev=1.1&content-type=text/plain |
1874 |
|
1875 |
Index: l-redesign-2.xml |
1876 |
=================================================================== |
1877 |
<?xml version='1.0' encoding="utf-8"?> |
1878 |
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd"> |
1879 |
|
1880 |
<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/doc/zh_cn/articles/l-redesign-2.xml,v 1.1 2007/10/03 17:50:18 r0bertz Exp $ --> |
1881 |
<!-- English CVS version: 1.2 --> |
1882 |
|
1883 |
<guide link="/doc/zh_cn/articles/l-redesign-2.xml" disclaimer="articles"> |
1884 |
<title>gentoo.org重新设计,第2部分:一个重生的站点</title> |
1885 |
|
1886 |
<author title="作者"> |
1887 |
<mail link="drobbins@g.o">Daniel Robbins</mail> |
1888 |
</author> |
1889 |
|
1890 |
<author title="译者"> |
1891 |
<mail link="developerWorks@×××.com">IBM developerWorks</mail> |
1892 |
</author> |
1893 |
|
1894 |
<author title="编辑"> |
1895 |
<mail link="zm3345@×××××.com">Zhou Mi</mail> |
1896 |
</author> |
1897 |
|
1898 |
<abstract> |
1899 |
您是否曾经在某天清晨醒来,意识到自己的个人开发网站其实并不那么好?如果是这样,那么您现在找对地方了。在本系列中,Daniel Robbins共享了它在使用诸如XML、XSLT和Python之类的技术重新设计www.gentoo.org网站时得到的经验。在此过程中,您也许还会发现一些优秀的方法适合于您的下一次网站重新设计。在这第2部分中,Daniel演示新文档系统并建立了一个日常CVS日志邮件列表。 |
1900 |
</abstract> |
1901 |
|
1902 |
<!-- The original version of this article was first published on IBM |
1903 |
developerWorks, and is property of Westtech Information Services. This |
1904 |
document is an updated version of the original article, and contains |
1905 |
various improvements made by the Gentoo Linux Documentation team --> |
1906 |
|
1907 |
<version>1.0</version> |
1908 |
<date>2005-10-10</date> |
1909 |
|
1910 |
<chapter> |
1911 |
<title>文档系统</title> |
1912 |
<section> |
1913 |
<body> |
1914 |
|
1915 |
<p> |
1916 |
如果您已经阅读了我撰写的“gentoo.org 重新设计”系列的<uri link="/doc/zh_cn/articles/l-redesign-1.xml">第一部分</uri>,那么您就知道我是Gentoo Linux的首席设计师,我要对Gentoo Linux网站负责。目前,这个站点还有许多不足。是的,它确实看似漂亮,但除了漂亮的图形之外,您会发现它实际上并没有满足主要预期用户──Gentoo Linux开发人员、用户和潜在用户──的需要。 |
1917 |
</p> |
1918 |
|
1919 |
<p> |
1920 |
上一次,我使用了以用户为中心的设计方法来为站点创建了一组优先级,然后使用这些优先级为重建gentoo.org创建行动计划。有两件事位于优先级列表的顶部:新的开发人员文档和用于向开发人员传达对CVS资源库所作更改的新邮件列表。虽然添加新的CVS邮件列表相对容易(可是,您会看到,它比我想象更困难),但新的开发人员文档却需要很多规划和工作。 |
1921 |
</p> |
1922 |
|
1923 |
<p> |
1924 |
我不仅需要创建一些实际文档(我长期以来一直忽略的任务),还必须选择新的主要文档要使用的正式XML语法。您知道,在几周之前,我还在创建原始HTML格式的文档。这的确是件麻烦事,因为如果这样做,那么内容(实际信息)将和显示(与显示相关的HTML标记)混合在一起。结果如何呢?一团糟,就是那样。编辑实际文档很困难,而改进整个站点的HTML尤其困难。 |
1925 |
</p> |
1926 |
|
1927 |
<p> |
1928 |
在本文中,我将自豪地演示这个站点新的灵活的XML文档解决方案。但首先,我将简要重述将CVS日志邮件列表添加到站点的经验。 |
1929 |
</p> |
1930 |
|
1931 |
</body> |
1932 |
</section> |
1933 |
<section> |
1934 |
<title>添加CVS日志邮件列表</title> |
1935 |
<body> |
1936 |
|
1937 |
<p> |
1938 |
CVS日志邮件列表的目的是通知开发人员:已经对CVS资源库做了新的提交。由于我已经安装了邮差邮件列表管理器(请参阅<uri link="#resources">参考资料</uri>),我认为创建这个新列表很容易。首先,我将只创建邮件列表,然后将正确的“hook”添加到CVS资源库,这样就会自动生成并发送出电子邮件,这些电子邮件描述了对源码的更改。 |
1939 |
</p> |
1940 |
|
1941 |
<p> |
1942 |
我首先开始研究资源库的CVSROOT中一个名为“loginfo”的特殊文件。理论上,通过修改这个文件,我可以指示CVS在对资源库执行任何提交(因此也做了修改)时执行一个脚本。因此,我创建了一个特殊loginfo脚本,并将它插入现有资源库。每当对源码进行修改时,它确实会向新的“gentoo-cvs”邮件列表发送电子邮件。 |
1943 |
</p> |
1944 |
|
1945 |
<p> |
1946 |
遗憾的是,这个解决方案并不完全如我所愿。首先,它生成了许多电子邮件消息──每个被修改的文件都有一条消息──其次,这些消息含义不清,有时甚至是空的!我迅速除去了loginfo脚本,并中断了gentoo-cvs邮件列表项目。很明显,CVS的loginfo hook不适合我的需要,我费了很大劲来搜寻可以帮助我解决问题的任何与loginfo相关的文档。 |
1947 |
</p> |
1948 |
|
1949 |
</body> |
1950 |
</section> |
1951 |
<section> |
1952 |
<title>cvs2cl.pl</title> |
1953 |
<body> |
1954 |
|
1955 |
<p> |
1956 |
几周之后,我开始寻找loginfo的替代物。这次,我做了一件聪明事,找到了<uri>freshmeat.net</uri>。在那里,我很快找到了自己要寻找的东西:来自<uri>red-bean.com</uri>的绝佳的cvs2cl.pl perl脚本(请参阅<uri link="#resources">参考资料</uri>)。<path>cvs2cl.pl</path>使用<c>cvs log</c>命令来直接连接到资源库并抽取适当的相关日志信息,而不是使用loginfo hook。此外,它并不生成相对含糊的CVS日志消息,而是将所有东西都重新格式化成可读的“更改日志(ChangeLog)”格式: |
1957 |
</p> |
1958 |
|
1959 |
<pre caption="cvs2cl.pl生成的输出"> |
1960 |
2001-04-09 20:58 drobbins |
1961 |
* app-doc/gentoo-web/files/xml/dev.xml: new fixes |
1962 |
2001-04-09 20:47 drobbins |
1963 |
* app-doc/gentoo-web/: gentoo-web-1.0.ebuild, |
1964 |
files/pyhtml/index.pyhtml, files/xml/gentoo-howto.xml: new gentoo-howto |
1965 |
fixes |
1966 |
2001-04-09 20:03 drobbins |
1967 |
* app-doc/gentoo-web/files/xml/dev.xml: typo fix |
1968 |
2001-04-09 20:02 drobbins |
1969 |
* app-doc/gentoo-web/files/pyhtml/index.pyhtml: little update |
1970 |
</pre> |
1971 |
|
1972 |
<p> |
1973 |
还可以指示<path>cvs2cl.pl</path>生成XML格式的输出,在下一篇文章中,我会利用这种技术将最新的“更改日志”结合到站点中新的开发人员部分。 |
1974 |
</p> |
1975 |
|
1976 |
</body> |
1977 |
</section> |
1978 |
<section> |
1979 |
<title>cvslog.sh脚本</title> |
1980 |
<body> |
1981 |
|
1982 |
<p> |
1983 |
以下是我现在用于生成日常“更改日志”电子邮件的脚本。首先,它将当前工作目录更改成已检出CVS资源库的位置。然后,它创建$yesterday和$today环境变量,它们包含了相应的RFC822格式的日期。请注意:这两个日期变量都将时间设置成“00:00”或午夜。然后,使用这些变量创建$cvsdate 变量,并将其传送给cvs2cl.pl以指定我感兴趣的日期范围──从昨天午夜到今天午夜的时间跨度。这样,$cvsdate变量就包含了一个日期规范,它通知cvs2cl.pl只对昨天的更改做日志,而不对其它更改做日志。 |
1984 |
</p> |
1985 |
|
1986 |
<p> |
1987 |
此外,我还创建了$nicedate变量(在邮件主题行中使用),并使用mutt邮件程序(以mailx兼容模式[请参阅<uri link="#resources">参考资料</uri>])将电子邮件发送到gentoo-cvs邮件列表: |
1988 |
</p> |
1989 |
|
1990 |
<pre caption="cvslog.sh脚本"> |
1991 |
#!/bin/bash |
1992 |
cd /usr/portage |
1993 |
cvs -q update -dP |
1994 |
yesterday=`date -d "1 day ago 00:00" -R` |
1995 |
today=`date -d "00:00" -R` |
1996 |
cvsdate=-d\'${yesterday}\<${today}\' |
1997 |
nicedate=`date -d yesterday +"%d %b %Y %Z (%z)"` |
1998 |
/home/drobbins/gentoo/cvs2cl.pl -f /home/drobbins/gentoo/cvslog.txt -l "${cvsdate}" |
1999 |
mutt -x gentoo-cvs -s "cvs log for $nicedate" <\ |
2000 |
/home/drobbins/gentoo/cvslog.txt |
2001 |
</pre> |
2002 |
|
2003 |
<p> |
2004 |
通过使用cron,我在每晚午夜时运行这个脚本。多亏有<path>cvs2cl.pl</path>,我的开发人员现在可以得到准确且可读的每日的CVS更新。 |
2005 |
</p> |
2006 |
|
2007 |
</body> |
2008 |
</section> |
2009 |
<section> |
2010 |
<title>文档项目</title> |
2011 |
<body> |
2012 |
|
2013 |
<p> |
2014 |
现在,讨论Gentoo Linux文档项目。新的文档系统涉及两组人或预期用户目录:文档创建人和文档读者。创建人需要不给创建带来妨碍的精心设计的XML语法;而根本不关心XML的读者想要生成的HTML文档既具功能性又具观赏性。实现的难点是如何创建一个满足这两种观众需要的完整系统。哦,我假设还有第三种“用户”──我,Web管理员和设计新系统的人。由于我打算在站点升级时与新的文档系统交互,因此我需要它可靠且灵活。 |
2015 |
</p> |
2016 |
|
2017 |
</body> |
2018 |
</section> |
2019 |
<section> |
2020 |
<title>就绪的HTML页面</title> |
2021 |
<body> |
2022 |
|
2023 |
<p> |
2024 |
首先,让我们讨论一下将根据我的主XML文件生成的已准备好待发布的HTML页面。要生成好的、可读的文档,我需要正确的XM标记的支持。例如,必须要有将注释、重要消息和警告插入文档主体(而且使它们在结果HTML中突出显示)的能力。此外,我必须要能插入几段代码,如果实际用户的输入可以以某种方式由程序输出得到补偿,那就太棒了。我甚至可以在源代码注释中加入语法高亮标签,使不同的代码用不同的颜色来显示,这样代码块就更易读了。 |
2025 |
</p> |
2026 |
|
2027 |
<p> |
2028 |
文档顶部应该有目录表(含有指向相应章节的超链接)、摘要、修订日期、版本和作者清单。当然,每个文档在其页面的最上部应该有一个页眉,该页眉包含了一个小的Gentoo Linux徽标。单击此徽标应该将您带到Gentoo Linux主页面。最后,很重要的一点是,每个文档都应该有一个页脚,它包含了版权信息和一个方便联系的电子邮箱地址。 |
2029 |
</p> |
2030 |
|
2031 |
</body> |
2032 |
</section> |
2033 |
<section> |
2034 |
<title>漂亮的新徽标</title> |
2035 |
<body> |
2036 |
|
2037 |
<p> |
2038 |
有大量要求需要满足,而我决定首先将精力集中在最有趣的部分,即出现在每个Gentoo Linux文档左上角的新Gentoo Linux徽标。我使用主页面上“gentoo”图形(使用优秀且免费的Blender 3D程序[请参阅<uri link="#resources">参考资料</uri>]创建的)中的“g”作为新的小徽标的基础图形。我略微调整了一下挤压设置,并添加了镀铬环境映射。最后,我安置了灯光和照相机,新的徽标就完成了。在将它导入Xara X(请参阅<uri link="#resources">参考资料</uri>)并添加了一些文本之后,就得到了以下结果: |
2039 |
</p> |
2040 |
|
2041 |
<figure link="/images/docs/l-redesign-02.gif" caption="新的Gentoo Linux徽标"/> |
2042 |
|
2043 |
<p> |
2044 |
我使用这个新徽标作为HTML颜色方案的其余部分的灵感,因此全部都使用略带紫色的主题。我大量使用级联样式表(CSS)来控制字体属性和间隔。一旦我有了象样的HTML原型,我开始将精力集中到新文档的内部──新的XML语法。我想要语法尽可能简单,因此我只创建了恰好足够多的XML标记,以允许正确组织文档,但没有多余标记。然后,我开始使用XSLT将XML转换成目标HTML。 |
2045 |
</p> |
2046 |
|
2047 |
</body> |
2048 |
</section> |
2049 |
<section> |
2050 |
<title>结果!</title> |
2051 |
<body> |
2052 |
|
2053 |
<p> |
2054 |
在许多次调整和从我的一个开发人员处获取大量反馈意见之后,新的文档系统达到了可以使用的地步。我立即开始了我们第一部新的开发指南“The Gentoo Linux Documentation Guide”(xml-guide.html)的工作,它包含了新XML格式的完整描述。这不仅允许其他开发人员开始使用新样式的文档,而且它是实际使用中的新文档系统的优秀示例。请务必阅读了该指南,并且完全理解新的XML语法。 |
2055 |
</p> |
2056 |
|
2057 |
</body> |
2058 |
</section> |
2059 |
<section> |
2060 |
<title>DocBook vs. Guide</title> |
2061 |
<body> |
2062 |
|
2063 |
<p> |
2064 |
如果您正在致力于自己的文档解决方案,那么您也许还应该考虑DocBook XML和SGML格式(请参阅<uri link="#resources">参考资料</uri>)。DocBook十分适合大型文档和书籍项目,它非常灵活,而且有许多(也许太多)功能。此外,有许多现有软件包可用于将DocBook XML/SGML转换成帮助页面、texinfo 文件、PostScript、PDF,当然,还有HTML格式。 |
2065 |
</p> |
2066 |
|
2067 |
<p> |
2068 |
我<e>没有</e>选择DocBook,因为轻量级XML语法最适合Gentoo的需要。目前,我们的XML guide语法有大约20个标记和大约10个属性。有限的标记集合使guide XML易于转换成其它格式,如HTML,而且还确保了在整个文档集中保持一定程度的一致性,因为格式是如此简单。由于已经有了自己的XML格式,我可以根据需要用新的标记扩展格式。我喜欢那个程度的控制。我将XML看作是一种人们应该用于以他们认为最实用的方法来构造数据的技术。换句话说,定义自己的元素和属性的能力是很宝贵的,我应该充分利用它。毕竟,它是XML的定义功能。 |
2069 |
</p> |
2070 |
|
2071 |
<p> |
2072 |
当然,创建自己的XML语法并不总是最佳解决方案,尤其是当数据互换对于您非常重要时。在所有的XML宣传中,有一件事通常会被忽略,那就是<e>不同XML格式之间的转换极其困难</e>。在许多情况下,两种格式不会100%兼容,而您将不得不违心地选择弃用数据和/或元数据,从而避免使用某些元素或属性,或者创建一种“超级格式”,它将容纳这两种XML格式的数据和元数据。在文档世界中,DocBook是作为“超级格式”的理想选择,因为它非常灵活;它可以轻易地容纳从各种源码导入的文档。 |
2073 |
</p> |
2074 |
|
2075 |
<p> |
2076 |
但是,DocBook的丰富性和灵活性也可能造成问题。例如,也许会有几百个您可能永远不需要的标记,而在XSLT中支持所有这些标记可能会使转换成其它格式变得更困难。因此,虽然DocBook对于转换自其它格式的文档来说是一个非常好的容器,但您自己的最简单XML语法却几乎始终更易于转换成其它格式。 |
2077 |
</p> |
2078 |
|
2079 |
<p> |
2080 |
最重要的事就是在牢记目标观众的需要的同时,认真评估所有潜在的解决方案。 |
2081 |
</p> |
2082 |
|
2083 |
</body> |
2084 |
</section> |
2085 |
<section> |
2086 |
<title>结束语</title> |
2087 |
<body> |
2088 |
|
2089 |
<p> |
2090 |
创建好新的文档系统之后,我将所有文档都转换成新的格式,并将新文档张贴到现有站点上。此外,我还创建了到gentoo-cvs邮件列表订阅页面的链接。这里的关键是我将这些功能都集成到现有站点,因此用户可以立即从这些改进中受益。 |
2091 |
</p> |
2092 |
|
2093 |
</body> |
2094 |
</section> |
2095 |
</chapter> |
2096 |
|
2097 |
<chapter id="resources"> |
2098 |
<title>参考资料</title> |
2099 |
<section> |
2100 |
<body> |
2101 |
|
2102 |
<ul> |
2103 |
<li> |
2104 |
请参阅使用XML,XSLT和Python等技术重新设计www.gentoo.org网站系列文章的其他部分: |
2105 |
<ul> |
2106 |
<li> |
2107 |
在<uri link="/doc/zh_cn/articles/l-redesign-1.xml">第1部分</uri>中,Daniel向读者演示了如何创建以用户为中心的行动计划,并介绍了pytext,这是一种嵌入式Python解释器。 |
2108 |
</li> |
2109 |
<li> |
2110 |
在<uri link="/doc/zh_cn/articles/l-redesign-3.xml">第3部分</uri>中,他将给网站一个新的外观(2001年7月)。 |
2111 |
</li> |
2112 |
<li> |
2113 |
在<uri link="/doc/zh_cn/articles/l-redesign-4.xml">第4部分</uri>中,Daniel完成了到XML/XSLT的转换,修复了Netscape 4.x浏览器的访问bug,还为网站添加了自动生成的XML Changelog(2001年8月)。 |
2114 |
</li> |
2115 |
</ul> |
2116 |
</li> |
2117 |
<li> |
2118 |
如果您还没有开始使用 Python,那您只是在自找麻烦。在<uri>http://www.python.org</uri>上可以找到它。 |
2119 |
</li> |
2120 |
<li> |
2121 |
请查看Xara X的主页<uri link="http://www.xara.com/">Xara.com</uri>──Xara X是一款极佳的Windows下的向量绘图软件包。它几乎没有一点多余功能,却有惊人的速度,建议您使用该软件。 |
2122 |
</li> |
2123 |
<li><uri>http://www.xslt.com</uri>上可以学到关于XSLT的更多知识。</li> |
2124 |
<li> |
2125 |
当您从清晨醒来,不妨看看Sablotron,这是一个又快又好的XSLT处理器,可以从<uri link="http://www-gingerall.com">Gingerall</uri>获得。 |
2126 |
</li> |
2127 |
<li> |
2128 |
在<uri link="http://www.red-bean.com/">Red-Bean</uri>上可以找到奇妙的<uri link="http://www.red-bean.com/cvs2cl/">cvs2cl.pl</uri>“CVS-to-ChangeLog”脚本。 |
2129 |
</li> |
2130 |
<li>请在<uri>http://www.docbook.org</uri>上了解有关DocBook的更多信息。</li> |
2131 |
<li> |
2132 |
如果您在寻找好的邮件列表管理器,请一定要访问<uri link="http://www.list.org">Mailman</uri>。 |
2133 |
</li> |
2134 |
<li> |
2135 |
请访问<uri link="http://www.mutt.org">www.mutt.org</uri>,以获取Mutt电子邮件客户机的最新版本。 |
2136 |
</li> |
2137 |
</ul> |
2138 |
|
2139 |
</body> |
2140 |
</section> |
2141 |
</chapter> |
2142 |
</guide> |
2143 |
|
2144 |
|
2145 |
|
2146 |
1.1 xml/htdocs/doc/zh_cn/articles/l-redesign-3.xml |
2147 |
|
2148 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-redesign-3.xml?rev=1.1&view=markup |
2149 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-redesign-3.xml?rev=1.1&content-type=text/plain |
2150 |
|
2151 |
Index: l-redesign-3.xml |
2152 |
=================================================================== |
2153 |
<?xml version='1.0' encoding="utf-8"?> |
2154 |
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd"> |
2155 |
|
2156 |
<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/doc/zh_cn/articles/l-redesign-3.xml,v 1.1 2007/10/03 17:50:18 r0bertz Exp $ --> |
2157 |
<!-- English CVS version: 1.2 --> |
2158 |
|
2159 |
<guide link="/doc/zh_cn/articles/l-redesign-3.xml" disclaimer="articles" lang="zh_cn"> |
2160 |
<title>gentoo.org重新设计,第3部分: 一个重生的站点</title> |
2161 |
|
2162 |
<author title="作者"> |
2163 |
<mail link="drobbins@g.o">Daniel Robbins</mail> |
2164 |
</author> |
2165 |
|
2166 |
<author title="译者"> |
2167 |
<mail link="developerWorks@×××.com">IBM developerWorks</mail> |
2168 |
</author> |
2169 |
|
2170 |
<author title="编辑"> |
2171 |
<mail link="zm3345@×××××.com">Zhou Mi</mail> |
2172 |
</author> |
2173 |
|
2174 |
<abstract> |
2175 |
您是否曾在某个清晨醒来,突然意识到自己开发的那个很酷的小网站实际上并不那么棒?如果是这样,别担心,很多人都是这样。在这个系列中,Daniel Robbins将与您共享他用XML、XSLT和Python等技术重新设计www.gentoo.org网站的经验。在这个过程中,您会发现一些用于重新设计 |
2176 |
您下一个网站的极佳方法。在本部分中,Daniel从整体上为其网站创建了一副新面孔。 |
2177 |
</abstract> |
2178 |
|
2179 |
<!-- The original version of this article was first published on IBM |
2180 |
developerWorks, and is property of Westtech Information Services. This |
2181 |
document is an updated version of the original article, and contains |
2182 |
various improvements made by the Gentoo Linux Documentation team --> |
2183 |
|
2184 |
<version>1.0</version> |
2185 |
<date>2005-10-10</date> |
2186 |
|
2187 |
<chapter> |
2188 |
<title>新的主页</title> |
2189 |
<section> |
2190 |
<title>目前的站点</title> |
2191 |
<body> |
2192 |
|
2193 |
<p> |
2194 |
到目前为止,www.gentoo.org已显现出重大改进。 <uri link="/doc/zh_cn/articles/l-redesign-2.xml">上一篇文章</uri>中,我用XML和XSLT设计了一种新的文档系统,所以,所有站点文档看起来都很棒,并可满足访问者的需求。然而,站点的整体外观并没有改变;那是因为:我实际上并没有触及用户最初访问我们的站点时所看到的HTML。我们的主页看起来仍然一样。 |
2195 |
</p> |
2196 |
|
2197 |
<p> |
2198 |
那么,现在该是改头换面的时候了。正如我在<uri link="/doc/zh_cn/articles/l-redesign-1.xml">第一篇文章</uri>中所提到的,我们的主页正变得过于拥挤,以至于没有空间用于扩展。您可以看到,我将很多内容放入了该页中: |
2199 |
</p> |
2200 |
|
2201 |
<p> |
2202 |
我无法继续向主页中放置一些重要链接和段落──没有地方可放。但我们很幸运,Web上的“地产”是完全免费的。 |
2203 |
</p> |
2204 |
|
2205 |
<p> |
2206 |
那么,为了解决这个问题,我将把我们唯一的一个主页(index.html)拆分成几个由主题确定类别的页面(index-about.html、index-download.html等),然后创建一个菜单系统,该系统将允许用户轻易地从一个类别页面移至另一个。用户访问<b>http://www.gentoo.org</b>时所装入的缺省页面将是“About Gentoo Linux”类别页面。这是个极佳的选择,因为它提供了有关该项目的一般信息,而该信息将引起初访者的兴趣。 |
2207 |
</p> |
2208 |
|
2209 |
</body> |
2210 |
</section> |
2211 |
<section> |
2212 |
<title>站点目标</title> |
2213 |
<body> |
2214 |
|
2215 |
<p> |
2216 |
现在,我将概括这个新的“类别页面”系统的目标,以及您可以应用到您自己的项目一些常规设计目标。然后,我们将看一下类别页面重新设计是如何满足这些目标的。 |
2217 |
</p> |
2218 |
|
2219 |
</body> |
2220 |
</section> |
2221 |
<section> |
2222 |
<title>模块性</title> |
2223 |
<body> |
2224 |
|
2225 |
<p> |
2226 |
新的类别页面系统需要是模块化的。这到底意味着什么?那么,目前我们已经在头脑中有了“About Gentoo Linux”和“Download/Install”类别,但是,以后我可能还会需要添加“About the Team”或“Support”类别。具有可以在以后轻易添加新类别的能力要求在设计阶段就安排好布局。我必须确保有空间用于导航菜单上的附加类别链接,并且页面的布局必须是通用的,以便用来显示很多不同类型的信息。这样,如果几个月后我再一次发现有不如意之处,那么,添加新类别将相对简单,而无需完全重新设计该站点。 |
2227 |
</p> |
2228 |
|
2229 |
<p> |
2230 |
还有一步对模块化设计也非常重要──使用XML和XSLT将显示与内容分开。如果您阅读了本系列的第2篇,那么您至少熟悉这种类型的设计。一旦创建了正确的XSL模板,我只需提供正确的XML就生成任意多的类别页面。与HTML不同,我的XML不包含与显示相关的信息;它完全是内容。我们将在本系列的第四部分(也是最后一部分)中看看这些类别页面的XML/XSLT实现。 |
2231 |
</p> |
2232 |
|
2233 |
</body> |
2234 |
</section> |
2235 |
<section> |
2236 |
<title>通用样式指南</title> |
2237 |
<body> |
2238 |
|
2239 |
<p> |
2240 |
新的类别布局在视觉上吸引人也是很重要的。请记住,当用户输入http://www.gentoo.org时,“About Gentoo Linux”类别页面将首先出现,因此,我希望这是个吸引人的页面。现在,“吸引人”一词对不同的人的含义也不同,但是,本文演示了几个很好的通用指南,我正在新类别页面的设计过程中使用这些指南,它们也应该适用于几乎任何网站。 |
2241 |
</p> |
2242 |
|
2243 |
</body> |
2244 |
</section> |
2245 |
<section> |
2246 |
<title>矩形外观</title> |
2247 |
<body> |
2248 |
|
2249 |
<p> |
2250 |
对于一般的页面布局来说,简单即是最好。如果要组织一些复杂的信息,为什么不使用一个主表来将页面拆分成不同的区域呢?这还可以帮助确保页面的不同部分对齐,从而构成一个整齐、吸引人的设计。例如,这种特殊类型的页面布局通常不是很吸引人: |
2251 |
</p> |
2252 |
|
2253 |
<figure link="/images/docs/l-redesign-03.gif" caption="不太理想的页面布局"/> |
2254 |
|
2255 |
<p> |
2256 |
然而,如果使用一个公共主网格来显示同一信息,站点就开始看起来整齐了许多: |
2257 |
</p> |
2258 |
|
2259 |
<figure link="/images/docs/l-redesign-04.gif" caption="对齐到网格后,事物变得不那么混乱"/> |
2260 |
|
2261 |
<p> |
2262 |
并且请记住:布局越简单,就可以在不干扰访问者的情况下向页面中填入更多信息。 |
2263 |
</p> |
2264 |
|
2265 |
</body> |
2266 |
</section> |
2267 |
<section> |
2268 |
<title>文本与背景颜色</title> |
2269 |
<body> |
2270 |
|
2271 |
<p> |
2272 |
下一步,我们要选择颜色。我不得不承认:我恰巧发现在深蓝色背景中显示鲜绿色文本十分吸引人。但是让我们正视它──不管它们看起来多奇异和漂亮,对于Web上的文本区域,深色背景是糟糕选择。人们希望在浅色背景中看到深色文本,而且我个人也认为我们应该提供用户所希望的颜色。 |
2273 |
</p> |
2274 |
|
2275 |
<p> |
2276 |
好,我应该澄清我的立场了。在深色背景上使用浅色文本对于显示段落信息来说是糟糕的选择,但是对于菜单栏或者一小簇链接来说的确十分吸引人和有效。换句话说,反色文本可能十分显眼,但确与您的主文本内容区的传统颜色方案相配;以后您就会感谢我。这还有助于确保将您的站点页面打印到纸上后也很漂亮。 |
2277 |
</p> |
2278 |
|
2279 |
</body> |
2280 |
</section> |
2281 |
<section> |
2282 |
<title>对比</title> |
2283 |
<body> |
2284 |
|
2285 |
<p> |
2286 |
除了深色文本/浅色背景事项之外,网站设计中没有很多严格的规则。例如,如果您喜欢深颜色,那么将页面顶部做成深蓝色就很棒。现在,请听清楚我说的话:如果将整个页面做成深蓝色,那就糟糕了。如果将页面的一部分(更适合于页面中没有很多文本的部分)做成深蓝色,您可能实际上在做一件很棒的事,因为深蓝色将与白色文本区形成极佳的对比,并给您的新站点增加了一些额外戏剧性。事实上,页面中很大一部分可以包含饱和色或深颜色;再次说明,只需确保用传统方式显示主文本内容即可。 |
2287 |
</p> |
2288 |
|
2289 |
</body> |
2290 |
</section> |
2291 |
<section> |
2292 |
<title>有效布局</title> |
2293 |
<body> |
2294 |
|
2295 |
<p> |
2296 |
我还想确保网页既不过于拥挤也不过于分散。我想我们中的所有人都会面临这个挑战;我们中有些人喜欢向页面中填入过多信息,以至于页面变得让人无法理解,而另一些人喜欢在页面上包含很多大的页边距和无用的空白区,以至于用户必须滚动几页才能找到所需信息。对于新的类别页面,我想使用最小页边距──我想,只需使内容可读即可。只有在内容变得过于拥挤时我才会使用空白区域。毕竟,使用这些类别页面就是为了解决空间问题,只要不影响可读性,那么在尽量小的空间集中放置尽量多的信息是最好的。 |
2297 |
</p> |
2298 |
|
2299 |
<p> |
2300 |
高密度信息还有另一个优势:用户不太需要滚动页面就可以找到所需信息。这使用户阅读页面时获得极大方便。(如果您不相信,可以设计几个模型页面然后自己查看。) |
2301 |
</p> |
2302 |
|
2303 |
</body> |
2304 |
</section> |
2305 |
<section> |
2306 |
<title>内容取代艺术</title> |
2307 |
<body> |
2308 |
|
2309 |
<p> |
2310 |
在设计该站点布局时,我很快认识到,重新设计网页应该是以可读和合理的方式显示内容(对访问者有用的实际信息)的很好时机,而不仅仅是另一个时机,即创造一种艺术效果或显示大量——哦──公司标识。这并不是说不允许有艺术效果,但如果为了创造这种效果而影响到内容的显示,那就不是为访问者着想。 |
2311 |
</p> |
2312 |
|
2313 |
<p> |
2314 |
有时,回过头来认识到访问我们站点的人们主要是寻找信息而不是荒谬地寻找Web设计新方法是一个很好的主意。如果这是您所努力克服的毛病,别担心:我也禁不住专注于考虑艺术方面的东西,而忽视了所有其它更重要的东西。 |
2315 |
</p> |
2316 |
|
2317 |
</body> |
2318 |
</section> |
2319 |
<section> |
2320 |
<title>结果</title> |
2321 |
<body> |
2322 |
|
2323 |
<p> |
2324 |
既然我们已经讨论了一些重新设计目标,让我们看一下新的gentoo.org类别页面。这是您在访问<b>http://www.gentoo.org</b>时所看到的欢迎页面: |
2325 |
</p> |
2326 |
|
2327 |
<figure link="/images/docs/l-redesign-05.gif" caption="新的www.gentoo.org主页"/> |
2328 |
|
2329 |
<p> |
2330 |
我必须承认我确实对这个重新设计感到高兴,并且我确实喜欢这个新站点的样子。请注意我是如何使用表来将页面分成四个区域的:左上部的徽标区、黑色菜单区、灰色信息栏区和白色主内容区。还要注意,这四个区域的整洁对齐使这个设计简单而吸引人。 |
2331 |
</p> |
2332 |
|
2333 |
<p> |
2334 |
现在看看颜色。如我前面所讲,我是极深色网站的狂热爱好者。然而,因为极深色站点难看,我达成了妥协:只在顶部区域使用深颜色,只在菜单区徽标和浮动“Gentoo Linux Features”框使用反色文本。因为这些页面部分不用于显示大量文本,所以这不会干扰我的访问者。相反,它们实际上成为主(白色)文本内容区的一个极佳陪衬。这是“Download/Install”类别页面的一个快照: |
2335 |
</p> |
2336 |
|
2337 |
<figure link="/images/docs/l-redesign-06.gif" caption="www.gentoo.org download/install页面"/> |
2338 |
|
2339 |
<p> |
2340 |
另一件只得指出的事是:您可能已经注意到蓝色的“飞碟”和红色的“gentoo”徽标都取自我以前的站点。我决定将这些图形集成到新设计中,以便那些常客对新的index.html主页感到熟悉。然而,在包括主页在内的所有其它页面中,我都省略了“飞碟”,以便在屏幕上显示更多信息。在每页中都保留了红色“gentoo”徽标,因为它可以使白色内容区在视觉上更吸引人,并吸引人们对类别标题的注意。 |
2341 |
</p> |
2342 |
|
2343 |
</body> |
2344 |
</section> |
2345 |
<section> |
2346 |
<title>导航菜单与标题</title> |
2347 |
<body> |
2348 |
|
2349 |
<p> |
2350 |
您可以看到,当前页面的名称在导航菜单中以鲜绿色突出显示,这是级联样式表(或CSS)的功劳,并且在主内容区中红色“gentoo”徽标下立即重复当前页面名称。虽然开始我觉得这没有必要,但我发现只以绿色突出显示当前页面的导航菜单项并不足以为用户提供足够的信息来告诉他们当前位于哪个页面。 |
2351 |
</p> |
2352 |
|
2353 |
<p> |
2354 |
尽管新站点看起来很整洁,但我正在向该页面中填入许多信息。这样做的一个好处是:在大多数显示分辨率下,访问者只需下滚就可以看完主文本。然而,所有超链接都应该是立即可见和可以访问的,这就要求用户不作垂直滚动。这使得站点从整体上更便于导航──实用性的一次重大胜利。 |
2355 |
</p> |
2356 |
|
2357 |
</body> |
2358 |
</section> |
2359 |
<section> |
2360 |
<title>迷失在Xara中</title> |
2361 |
<body> |
2362 |
|
2363 |
<p> |
2364 |
只观看这个站点并不能告诉您重新设计的过程是什么样的。实际上,我从重新设计一开始就犯下一些重大逻辑错误。我最大的错误是一开始就启动Xara,试图为类别页面设计新外观。 |
2365 |
</p> |
2366 |
|
2367 |
<p> |
2368 |
我曾经在Xara中浪费了许多时间,几乎只考虑视觉上的花哨设计,而不是页面布局。这样做的结果是,本末倒置并最终创建了大约20幅设计原型,但最终不得不丢掉。最后,这些原型对我来说毫无用处,因为他们不能处理如何显示内容的问题。</p> |
2369 |
|
2370 |
<p> |
2371 |
最终,我重新找回感觉,退出Xara,启动文本编辑器,然后写下将出现在页面中的原始文本。编写完内容之后,我设计了一个通用页面布局,将该文本显示给用户──还没有设计颜色方案和视觉效果。那时(并且只在那时),我才返回到Xara并完成站点的新外观,开发出了颜色方案并改进了我们的徽标。这一次,图形设计过程很顺利也相对较快,因为我已有一个框架(文本和布局)来指引我的工作。如果没有这个结构,我可能要花上我的余生来对付Xara,并为新站点设计出上千个假想设计可能性。 |
2372 |
</p> |
2373 |
|
2374 |
<p> |
2375 |
当您重新设计站点时,请记住:首先是内容,其次是布局,而图形修饰则是第三位。若采用这种方法,您将最终节约许多时间。 |
2376 |
</p> |
2377 |
|
2378 |
</body> |
2379 |
</section> |
2380 |
<section> |
2381 |
<title>以用户为中心的IRC</title> |
2382 |
<body> |
2383 |
|
2384 |
<p> |
2385 |
我确实在设计过程中犯了几个错误,但是我还做了几件正确的事,其中的一件是允许Gentoo Linux开发人员在我的设计过程中对我的工作进行评论并给出意见。您可能会在我第一篇文章中回忆起,我的行动计划将开发人员作为我的最重要观众,因此很明显,让现有的开发人员参与设计是一项明智之举。 |
2386 |
</p> |
2387 |
|
2388 |
<p> |
2389 |
要做到这点很简单。我只需象以往那样,让一台IRC客户机持续运行并连入我们的IRC频道即可(请参阅参考资料),然后每当我有重大进展,我都会生成一个当前站点的.png快照,并将其张贴到我们的Web服务器。然后,频道中的每个人都可以实时地查看,并对我的工作提出意见。 |
2390 |
</p> |
2391 |
|
2392 |
<p> |
2393 |
这些开发人员就好比我的晴雨表,让我知道哪些设计和颜色是最受欢迎的,哪些布局样式最佳。如果站点设计变得过于拥挤或复杂,就会有人告诉我,然后我就相应地调整HTML。当类别页面设计即将完成时,我就开始创建HTML/图像的tar压缩文件,以便开发人员可以尝试代码并作必要改正。这样,IRC频道就允许以一种真正以用户为中心的方式开发HTML。最后一点(但并非不重要),Gentoo Linux开发人员确实帮助我调试了HTML代码,以便可以在各种现代浏览器中以优化方式显示它们。 |
2394 |
</p> |
2395 |
|
2396 |
</body> |
2397 |
</section> |
2398 |
<section> |
2399 |
<title>下一篇</title> |
2400 |
<body> |
2401 |
|
2402 |
<p> |
2403 |
好,现在就到这。请在我的下一篇文章中和我一起最终将整个站点转变成完全模块化的、基于XML/XSLT的系统。那应该会使您兴奋,并为您带来一个查看许多有趣的幕后XML开发细节的机会。 |
2404 |
</p> |
2405 |
|
2406 |
</body> |
2407 |
</section> |
2408 |
</chapter> |
2409 |
|
2410 |
<chapter> |
2411 |
<title>参考资料</title> |
2412 |
<section> |
2413 |
<body> |
2414 |
|
2415 |
<ul> |
2416 |
<li> |
2417 |
请参阅使用XML,XSLT和Python等技术重新设计www.gentoo.org网站系列文章的其他部分: |
2418 |
<ul> |
2419 |
<li> |
2420 |
在<uri link="/doc/zh_cn/articles/l-redesign-1.xml">第1部分</uri>中,Daniel向读者演示了如何创建以用户为中心的行动计划,并介绍了pytext,这是一种嵌入式Python解释器(2001年3月)。 |
2421 |
</li> |
2422 |
<li> |
2423 |
在<uri link="/doc/zh_cn/articles/l-redesign-2.xml">第2部分</uri>中,Daniel将展示新的文档系统以及建立一个CVS-log邮件日志列表(2001年3月)。 |
2424 |
</li> |
2425 |
<li> |
2426 |
在<uri link="/doc/zh_cn/articles/l-redesign-4.xml">第4部分</uri>中,Daniel完成了到XML/XSLT的转换,修复了Netscape |
2427 |
4.x浏览器的访问bug,还为网站添加了自动生成的XML Changelog(2001年8月)。 |
2428 |
</li> |
2429 |
</ul> |
2430 |
</li> |
2431 |
<li> |
2432 |
访问“万维网联盟”(或W3C)中的<uri link="http://www.w3.org/Style/CSS/">CSS页面</uri>来了解有关级联样式表(CSS)的更多信息。 |
2433 |
</li> |
2434 |
<li> |
2435 |
请查看Xara X的主页<uri link="http://www.xara.com/">Xara.com</uri>──Xara X是一款极佳的Windows下的向量绘图软件包。它几乎没有一点多余功能,却有惊人的速度,建议您使用该软件。 |
2436 |
</li> |
2437 |
<li><uri>http://www.xslt.com</uri>上可以学到关于XSLT的更多知识。</li> |
2438 |
<li> |
2439 |
当您清醒过来,不妨看看Sablotron,这是一个又快又好的XSLT处理器,可以从<uri link="http://www-gingerall.com">Gingerall</uri>获得。 |
2440 |
</li> |
2441 |
</ul> |
2442 |
|
2443 |
</body> |
2444 |
</section> |
2445 |
</chapter> |
2446 |
</guide> |
2447 |
|
2448 |
|
2449 |
|
2450 |
1.1 xml/htdocs/doc/zh_cn/articles/l-redesign-4.xml |
2451 |
|
2452 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-redesign-4.xml?rev=1.1&view=markup |
2453 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/zh_cn/articles/l-redesign-4.xml?rev=1.1&content-type=text/plain |
2454 |
|
2455 |
Index: l-redesign-4.xml |
2456 |
=================================================================== |
2457 |
<?xml version='1.0' encoding="utf-8"?> |
2458 |
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd"> |
2459 |
|
2460 |
<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/doc/zh_cn/articles/l-redesign-4.xml,v 1.1 2007/10/03 17:50:18 r0bertz Exp $ --> |
2461 |
<!-- English CVS version: 1.2 --> |
2462 |
|
2463 |
<guide link="/doc/zh_cn/articles/l-redesign-4.xml" disclaimer="articles" lang="zh_cn"> |
2464 |
<title>gentoo.org重新设计,第4部分:一个重生的站点</title> |
2465 |
|
2466 |
<author title="作者"> |
2467 |
<mail link="drobbins@g.o">Daniel Robbins</mail> |
2468 |
</author> |
2469 |
|
2470 |
<author title="译者"> |
2471 |
<mail link="developerWorks@×××.com">IBM developerWorks</mail> |
2472 |
</author> |
2473 |
|
2474 |
<author title="编辑"> |
2475 |
<mail link="zm3345@×××××.com">Zhou Mi</mail> |
2476 |
</author> |
2477 |
|
2478 |
<abstract> |
2479 |
您是否曾在某个清晨醒来,突然意识到自己开发的那个很酷的小网站实际上并不那么棒?如果是这样,别担心,很多人都是这样。在这个系列中,Daniel Robbins将与您共享他用XML、XSLT和Python等技术重新设计www.gentoo.org网站的经验。在本文中,Daniel完成了到XML/XSLT的转换,修复了一些Netscape 4.x浏览器兼容性错误,并向该站点添加了一个自动生成的“XML更改日志”。 |
2480 |
</abstract> |
2481 |
|
2482 |
<!-- The original version of this article was first published on IBM |
2483 |
developerWorks, and is property of Westtech Information Services. This |
2484 |
document is an updated version of the original article, and contains |
2485 |
various improvements made by the Gentoo Linux Documentation team --> |
2486 |
|
2487 |
<version>1.1</version> |
2488 |
<date>2005-10-10</date> |
2489 |
|
2490 |
<chapter> |
2491 |
<title>最后一番润色</title> |
2492 |
<section> |
2493 |
<title>有了新外观,但是……</title> |
2494 |
<body> |
2495 |
|
2496 |
<p> |
2497 |
在上一篇文章的末尾,Gentoo Linux网站有了一副全新的面孔,但是还有一些工作没有完成。在本文(也是本系列的最后一部分)中,我最终对这个站点进行最后一番润色,结果产生一个功能完备、考究和模块化且便于日后修改的基于XML的站点。这是接上一篇文章中关于站点未讨论完的部分: |
2498 |
</p> |
2499 |
|
2500 |
</body> |
2501 |
</section> |
2502 |
<section> |
2503 |
<title>尚需处理的问题</title> |
2504 |
<body> |
2505 |
|
2506 |
<p> |
2507 |
首先,虽然该站点有了一个全新外观,但只有站点的文档部分是基于XML的。主“类别”页面仍然是原始的HTML格式,需要将其转换成XML/XSLT方案,以使它们更便于维护和扩充。 |
2508 |
</p> |
2509 |
|
2510 |
<p> |
2511 |
另外,我的开发人员还发现几个原始HTML本身的问题。当用Netscape 4.77浏览时,站点看起来特别难看──显然,这是个问题。另外,在更多现代浏览器中还有其它一些较小的显示问题,其中最讨厌的是有一条细竖线没有完全向下延展到整个页面,从而破坏了我们的飞碟好手正在讲述主内容区这样一个感觉。另外,我们的文档页与具有更考究外观的新主类别页没有完全配合好──很明显需要更新一些东西。 |
2512 |
</p> |
2513 |
|
2514 |
</body> |
2515 |
</section> |
2516 |
<section> |
2517 |
<title>目标</title> |
2518 |
<body> |
2519 |
|
2520 |
<p> |
2521 |
这是Gentoo Linux站点的最后修改计划。首先,我们将完全修改主页HTML,保持总体外观不变,但使该页面与浏览器更兼容。同时,还会做几项访问者所建议的、与显示有关的改进,并且还会修复现有“guide”文档系统的浏览器兼容性问题。 |
2522 |
</p> |
2523 |
|
2524 |
<p> |
2525 |
下一步,将把站点完全转变为XML和XSLT。在本文最后,对站点所做的的任何更改都将通过修改XML和XSLT而不是直接编辑HTML来完成,现在,这可以在xsltproc(请参阅参考资料)的帮助下自动生成。这将极大简化站点的维护工作。因为Gentoo Linux是一个由社区开发的项目,所以,反过来这将允许我们的开发人员(和我)按照需要维护和改进站点。我确实对此感到兴奋,因为它将节省我一些时间,并确保以最新内容欢迎我们的访问者。 |
2526 |
</p> |
2527 |
|
2528 |
</body> |
2529 |
</section> |
2530 |
<section> |
2531 |
<title>兼容性问题</title> |
2532 |
<body> |
2533 |
|
2534 |
<p> |
2535 |
虽然Netscape 4.x仍然是一个使用非常广泛的浏览器,但我很难确定:为了使站点在这种浏览器中显示得好一些,究竟需要克服多少困难。我应该只确保站点可读(没有任何重大错误)呢?还是应该尽我所能以使该站点在Netscape 4.x中看起来绝对完美──即使那样做需要少使用或不使用CSS并向现有HTML中添加奇怪的兼容性方法? |
2536 |
</p> |
2537 |
|
2538 |
<p> |
2539 |
最后,我决定对HTML做几项重大更改,以便站点在Netscape 4.x中看起来仍然很好,而不是过于关注与表间距和字体显示问题相关的较小错误。这里是对该站点的HTML所作的一些更改,以使所有内容都与4.x兼容。(Gentoo Linux开发小组已经提交了几个这样的修正。) |
2540 |
</p> |
2541 |
|
2542 |
<p> |
2543 |
首先,Netscape 4.x有一个错误,可导致块元素的CSS背景色被错误显示。例如,下面是指南文档的某个特定部分 期望的显示效果: |
2544 |
</p> |
2545 |
|
2546 |
<figure link="/images/docs/l-redesign-07.gif" caption="IE5中的一个样本指南文档"/> |
2547 |
|
2548 |
<p> |
2549 |
下面是使用CSS指定了背景色时,用Netscape 4.x显示同一部分的效果: |
2550 |
</p> |
2551 |
|
2552 |
<figure link="/images/docs/l-redesign-08.gif" caption="Netscape 4.7中的一个样本指南文档;尚需一些修正"/> |
2553 |
|
2554 |
<p> |
2555 |
这很难看。要修复它,将现有块级的元素(例如这个……) |
2556 |
</p> |
2557 |
|
2558 |
<pre caption="段落样本"> |
2559 |
<p class="note">This paragraph doesn't look so good in 4.x</p> |
2560 |
</pre> |
2561 |
|
2562 |
<p> |
2563 |
……用下面的表来替换: |
2564 |
</p> |
2565 |
|
2566 |
<pre caption="表格样本"> |
2567 |
<table width="100%" border="0" cellpadding="0" cellspacing="0"> |
2568 |
<tr> |
2569 |
<td bgcolor="#ddffff"><p class="note"> |
2570 |
This looks a whole lot better in 4.x</p></td> |
2571 |
</tr> |
2572 |
</table> |
2573 |
</pre> |
2574 |
|
2575 |
<p> |
2576 |
这种方法修复背景显示问题。然而,这种“修复”还需要在HTML中包括颜色信息,这首先就破坏了使用CSS的好处。这是一种不幸的情况,特别是对于象我这样的CSS爱好者,但是Netscape |
2577 |
4.x兼容性需要这样做。 |
2578 |
</p> |
2579 |
|
2580 |
</body> |
2581 |
</section> |
2582 |
<section> |
2583 |
<title>重建HTML</title> |
2584 |
<body> |
2585 |
|
2586 |
<p> |
2587 |
现在该处理那条不总是一直延伸到屏幕底部的黑色竖线的问题了。我无法找到一个方案来解决这个问题,使之既能在4.x又在5.x浏览器中工作;每一个5.x版本都会触发Netscape 4.x中的错误,而每一个与4.x兼容的版本在5.x浏览器中看起来都很糟糕。因此,我决定简单地除去整条黑线:最后,该站点可以在很多浏览器中工作。下一步,我将创建一个类似于guide的语法以创建主页。</p> |
2588 |
|
2589 |
</body> |
2590 |
</section> |
2591 |
<section> |
2592 |
<title>着手XML</title> |
2593 |
<body> |
2594 |
|
2595 |
<p> |
2596 |
我没有为主页实现全新标记集,相反,我认为使用尽可能多的“guide”XML文档标记是个好主意(有关guide XML格式的详细信息,请参阅本系列的第2部分)。因此,我除去了一些新的XSL,而使用我的guide XSL作为我的工作模板。一两个小时之后,我就得到了一个功能齐备的、用于将类似于guide的语法变成HTML主页的XSL变换集。新主页的修订版2看起来类似于: |
2597 |
</p> |
2598 |
|
2599 |
<figure link="/images/docs/l-redesign-09.gif" caption="新主页修订版"/> |
2600 |
|
2601 |
<p> |
2602 |
既然主页使用一个新的XML/XSLT后端,我就将我的注意力转移到“guide”系统的HTML输出。我不仅需要修复很多Netscape 4.7兼容性错误,而且还要进一步更新生成的HTML和图形,以便它们能与那些新修改的主页很好地配合。这时我想到了一个主意:为什么不简单地对我的新主页XML/XSL进行略微调整,以便它还可以为我的文档生成HTML?毕竟,我刚刚添加了对几乎每一个“guide”XML标记的支持,以便它们可用于主页内容。 |
2603 |
</p> |
2604 |
|
2605 |
<p> |
2606 |
结果这个解决方案确实很容易实现。我仅仅调整了新的XSLT文件,以便它可以除去左边的“链接栏”并在处理文档页面时对输出HTML作其它几点较小的更改。既然大多数XSLT仍然相同,我可以对guide文档和类别页面使用一个主XSLT模板集。 |
2607 |
</p> |
2608 |
|
2609 |
<figure link="/images/docs/l-redesign-10.gif" caption="新XSL的工作原理"/> |
2610 |
|
2611 |
<p> |
2612 |
现在,我不仅只维护一个XSLT模板集,而且因为两种输出HTML风格都基于同一主文档,它们现在还共享同一CSS样式表。这意味者无需在两个截然不同的样式表和输出HTML集之间“同步外观”。并且您可以看到,新的文档HTML与新主页配合得很完美。 |
2613 |
</p> |
2614 |
|
2615 |
<figure link="/images/docs/l-redesign-11.gif" caption="新文档页面与新主页完美配合"/> |
2616 |
|
2617 |
</body> |
2618 |
</section> |
2619 |
<section> |
2620 |
<title>XML实现</title> |
2621 |
<body> |
2622 |
|
2623 |
<p> |
2624 |
实际的实现相当简单;我现有的guide XML语法要求每个文档都是单一主<guide>元素的一部分。为添加对主类别页面的支持,我创建了一个新的主元素:<mainpage>。为创建主类别页面,我将所有内容都放在<mainpage>元素中、而不是<guide>元素中,并且XSLT对输出作了适当更改。除此之外,唯一需要的重大更改是添加可选的<sidebar>元素,该元素用于指定主类别页面上浮动表的内容。现有的<guide>XSLT模板看起来类似于: |
2625 |
</p> |
2626 |
|
2627 |
<pre caption="XSLT模板"> |
2628 |
<xsl:template match="/guide"> |
2629 |
<html> |
2630 |
<head> |
2631 |
guide header goes here |
2632 |
</head> |
2633 |
<body> |
2634 |
top part of guide body HTML content goes here |
2635 |
<!--next, we insert our content--> |
2636 |
<xsl:apply-templates select="chapter" /> |
2637 |
bottom part of guide body HTML content goes here |
2638 |
</body> |
2639 |
</html> |
2640 |
</xsl:template> |
2641 |
</pre> |
2642 |
|
2643 |
<p> |
2644 |
如果您不是很熟悉XSLT,则这个模板告诉XSLT处理程序用HTML文档的外壳替换<guide></guide>标记,并且将模板重复应用到<guide>元素内的任何<chapter>元素(开始/结束标记对)并将产生的结果输出插入到HTML外壳中间。 |
2645 |
</p> |
2646 |
|
2647 |
<p> |
2648 |
这样,为了添加对主类别页面的支持,我需要指定:如果所有内容都恰巧包括在单一<mainpage>元素中,应该使用一个不同的HTML外壳。要做到这点,我添加了一个新的模板,如下所示: |
2649 |
</p> |
2650 |
|
2651 |
<pre caption="新模板"> |
2652 |
<xsl:template match="/mainpage"> |
2653 |
<html> |
2654 |
<head> |
2655 |
mainpage header goes here |
2656 |
</head> |
2657 |
<body> |
2658 |
top part of mainpage body HTML content goes here |
2659 |
<!--next, we insert our content--> |
2660 |
<xsl:apply-templates select="chapter" /> |
2661 |
bottom part of mainpage body HTML content goes here |
2662 |
</body> |
2663 |
</html> |
2664 |
</xsl:template> |
2665 |
</pre> |
2666 |
|
2667 |
<p> |
2668 |
因为几乎每一个其它的XML元素(从<chapter>开始之后的所有元素)都为guide和主类别页面产生相同的HTML输出,所以几乎每一个其它的XSLT模板都可以为这两种类型的页面所共享。因此,我们只需使用一个指定两种“HTML外壳”的XSLT文件和一个从XML转换到HTML的公用XSLT模板集就可以很好地完成任务。象往常一样,代码重用无疑是个好东西。 |
2669 |
</p> |
2670 |
|
2671 |
</body> |
2672 |
</section> |
2673 |
<section> |
2674 |
<title>“更改日志”页面</title> |
2675 |
<body> |
2676 |
|
2677 |
<p> |
2678 |
您可能记得,在本系列的“第2部分”中,我提到过cvs2cl.pl“CVS 更改日志”生成脚本(请参阅<uri link="#resources">参考资料</uri>)可以产生XML输出,并且我最终要使用这个特性作为每天都会出现在新网站上的“CVS更改日志”页面的基础。现在,有了新的XML后端的支持,添加新的“更改日志”不过是小菜一碟。这是cvslog.sh脚本的增强版本,它还负责处理从XML到HTML的转换: |
2679 |
</p> |
2680 |
|
2681 |
<pre caption="升级的cvslog.sh脚本"> |
2682 |
#!/bin/bash |
2683 |
#various paths |
2684 |
HOMEDIR=/home/drobbins |
2685 |
CVSDIR=${HOMEDIR}/gentoo/gentoo-x86 |
2686 |
OUTLOG=${HOMEDIR}/gentoo/xmlcvslog.txt |
2687 |
OUTMAIL=${HOMEDIR}/gentoo/cvslog.txt |
2688 |
WEBDIR=/usr/local/httpd/htdocs |
2689 |
XSLTP=/opt/gnome/bin/xsltproc |
2690 |
TMPFILE=${HOMEDIR}/gentoo/xmlcvslog.tmp |
2691 |
USER=drobbins |
2692 |
#if $CVSMAIL is undefined, set it to "yes" |
2693 |
if [ -z "$CVSMAIL" ] |
2694 |
then |
2695 |
export CVSMAIL="yes" |
2696 |
fi |
2697 |
#the main script |
2698 |
cd $CVSDIR |
2699 |
cvs -q update -dP |
2700 |
yesterday=`date -d "1 day ago 00:00" -R` |
2701 |
today=`date -d "00:00" -R` |
2702 |
cvsdate=-d\'${yesterday}\<${today}\' |
2703 |
nicedate=`date -d yesterday +"%d %b %Y %Z (%z)"` |
2704 |
#generate cvs2cl.pl XML output |
2705 |
/usr/bin/cvs2cl.pl --xml -f $OUTLOG -l "${cvsdate}" |
2706 |
#use sed to remove "xmlns=" from cvs2cl.pl output |
2707 |
/usr/bin/sed -e 's/xmlns=".*"//' $OUTLOG > ${OUTLOG}.2 |
2708 |
#convert cvs2cl.pl XML output to guide format using $XLSTP |
2709 |
$XSLTP ${WEBDIR}/xsl/cvs.xsl ${OUTLOG}.2 > $TMPFILE |
2710 |
#convert guide XML output to HTML format using $XLSTP |
2711 |
$XSLTP ${WEBDIR}/xsl/guide-main.xsl |
2712 |
$TMPFILE > ${WEBDIR}/index-changelog.html |
2713 |
#fix perms |
2714 |
chmod 0644 ${WEBDIR}/index-changelog.html |
2715 |
#automatically send cvs mail if $CVSMAIL is set to "yes" |
2716 |
if [ "$CVSMAIL" = "yes" ] |
2717 |
then |
2718 |
/usr/bin/cvs2cl.pl -f ${OUTMAIL} -l "${cvsdate}" |
2719 |
mutt -x gentoo-cvs -s "cvs log for $nicedate" > ${OUTMAIL} |
2720 |
fi |
2721 |
</pre> |
2722 |
|
2723 |
<p> |
2724 |
虽然该脚本看起来比以前的版本复杂得多,但它实际上只添加了四个或五个关键行;其余添加的行不是注释就是环境变量定义。 |
2725 |
</p> |
2726 |
|
2727 |
<p> |
2728 |
以下是cvslog.sh脚本中与XML相关的新部分的工作原理。首先,我们调用cvs2cl.pl,然后指使它生成一个基于XML、并包含昨天修改过的所有文件的“更改日志”。然后,通过sed运行这个XML输出,以从XML中除去一个不需要的xmlns=属性。下一步,我们将这个作过轻微改动的XML传递给xsltproc,并告诉它应用在cvs.xsl中发现的处理指令;这些指令将来自cvs2cl.pl的XML输出变换成正确的guide XML文档。最后,我们再次使用xsltproc将这个guide XML文档转换成可在Web上发布的HTML,该HTML被管道输出至Web服务器的htdocs目录。生成的“HTML更改日志”是完整的,这就是结果: |
2729 |
</p> |
2730 |
|
2731 |
<figure link="/images/docs/l-redesign-12.gif" caption="自动生成的“更改日志”页面"/> |
2732 |
|
2733 |
<p> |
2734 |
您可能对包含在cvs.xsl中的XSLT的简单性感到惊讶。其中,我们为<changelog>、<entry>和<file>指定了三个模板。我们还引用了源XML中的其它几个标记,包括<date>、<author>和<msg>(cvs2cl.pl使用它们来指定提交者的注释)。考虑到它大约只有35行,cvs.xsl做得已经相当多了。 |
2735 |
</p> |
2736 |
|
2737 |
<pre caption="cvs.xsl"> |
2738 |
<?xml version='1.0' encoding="iso-8859-1"?> |
2739 |
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> |
2740 |
<xsl:output encoding="iso-8859-1" method="xml" indent="yes"/> |
2741 |
<xsl:template match="/changelog"> |
2742 |
<mainpage id="changelog"> |
2743 |
<title>Gentoo Linux Development Changelog for <xsl:value-of select="entry/date"/></title> |
2744 |
<author title="script">cvs-xml.xsl</author> |
2745 |
<standout> |
2746 |
<title>About the Development Changelog</title> |
2747 |
<body> |
2748 |
This page contains a daily Changelog, listing all modifications made to our |
2749 |
CVS tree on <xsl:value-of select="entry/date"/> (yesterday). |
2750 |
</body> |
2751 |
</standout> |
2752 |
<version>1.0.0</version> |
2753 |
<date><xsl:value-of select="entry/date"/></date> |
2754 |
<chapter> |
2755 |
<xsl:apply-templates select="entry"/> |
2756 |
</chapter> |
2757 |
</mainpage> |
2758 |
</xsl:template> |
2759 |
<xsl:template match="entry"> |
2760 |
<section> |
2761 |
<title>Files modified by <xsl:value-of select="author"/> at |
2762 |
<xsl:value-of select="time"/> |
2763 |
</title> |
2764 |
<body> |
2765 |
<note><xsl:value-of select="msg"/></note> |
2766 |
<ul> |
2767 |
<xsl:apply-templates select="file"/> |
2768 |
</ul> |
2769 |
</body> |
2770 |
</section> |
2771 |
</xsl:template> |
2772 |
<xsl:template match="file"> |
2773 |
<li><path><xsl:value-of select="name"/></path>, <xsl:value-of select="revision"/></li> |
2774 |
</xsl:template> |
2775 |
</xsl:stylesheet> |
2776 |
</pre> |
2777 |
|
2778 |
</body> |
2779 |
</section> |
2780 |
<section> |
2781 |
<title>项目完成!</title> |
2782 |
<body> |
2783 |
|
2784 |
<p> |
2785 |
从开始重新设计Gentoo Linux网站,我们就创建了一个以用户为中心的行动计划,设计了一个新的基于XML的文档系统,一个新的徽标,一个新的站点外观,将所有剩余部分转换成XML,并添加了新的基于XML的“更改日志”页面。唷!我希望您在随我进行的过程中得到欢乐,并从中发现很多好主意和灵感。我已经收到了几个关于对更多信息和与重新设计相关的代码的请求,因此,我建立了一个特殊的<uri link="http://www.gentoo.org/proj/en/site.xml">Gentoo Linux XML项目</uri>页面,该页面包含www.gentoo.org所使用的最新的XML、XSLT、脚本和文档。除了访问“项目”页面之外,请务必查看以下所列的有价值资源。 |
2786 |
</p> |
2787 |
|
2788 |
</body> |
2789 |
</section> |
2790 |
</chapter> |
2791 |
|
2792 |
<chapter> |
2793 |
<title>参考资料</title> |
2794 |
<section> |
2795 |
<body> |
2796 |
|
2797 |
<ul> |
2798 |
<li> |
2799 |
如果您有兴趣使用Gentoo Linux guide XML系统为基础开发自己的项目,请访问<uri link="http://www.gentoo.org/proj/en/site.xml">Gentoo Linux XML项目</uri>页面。所有最新的XML/XSLT文档都能在这里找到。 |
2800 |
</li> |
2801 |
<li> |
2802 |
请参阅使用XML,XSLT和Python等技术重新设计www.gentoo.org网站系列文章的其他部分: |
2803 |
<ul> |
2804 |
<li> |
2805 |
在<uri link="/doc/zh_cn/articles/l-redesign-1.xml">第1部分</uri>中,Daniel向读者演示了如何创建以用户为中心的行动计划,并介绍了pytext,这是一种嵌入式Python解释器(2001年3月)。 |
2806 |
</li> |
2807 |
<li> |
2808 |
在<uri link="/doc/zh_cn/articles/l-redesign-2.xml">第2部分</uri>中,Daniel将展示新的文档系统以及建立一个CVS-log邮件日志列表(2001年3月)。 |
2809 |
</li> |
2810 |
<li> |
2811 |
在<uri link="/doc/zh_cn/articles/l-redesign-3.xml">第3部分</uri>中,他将给网站一个新的外观(2001年7月)。 |
2812 |
</li> |
2813 |
</ul> |
2814 |
</li> |
2815 |
<li> |
2816 |
访问“万维网联盟”(或 W3C)中的<uri link="http://www.w3.org/Style/CSS/">CSS页面</uri>来了解有关CSS(级联样式表)的更多信息。您可以找到有关<uri link="http://www.w3.org/XML">XML</uri>和<uri link="http://www.w3.org/TR/xslt">XSLT</uri>的更多信息以及大量其它技术。 |
2817 |
</li> |
2818 |
<li> |
2819 |
请查看Xara X的主页<uri link="http://www.xara.com/">Xara.com</uri>──Xara X是一款极佳的Windows下的向量绘图软件包。它几乎没有一点多余功能,却有惊人的速度,建议您使用该软件。 |
2820 |
</li> |
2821 |
<li><uri>http://www.xslt.com</uri>上可以学到关于XSLT的更多知识。</li> |
2822 |
<li> |
2823 |
当您清醒过来,不妨看看Sablotron,这是一个又快又好的XSLT处理器,可以从<uri link="http://www-gingerall.com">Gingerall</uri>获得。 |
2824 |
</li> |
2825 |
</ul> |
2826 |
|
2827 |
</body> |
2828 |
</section> |
2829 |
</chapter> |
2830 |
</guide> |
2831 |
|
2832 |
|
2833 |
|
2834 |
-- |
2835 |
gentoo-commits@g.o mailing list |