Gentoo Archives: gentoo-commits

From: "Le Zhang (r0bertz)" <r0bertz@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo commit in xml/htdocs/doc/zh_cn/articles: l-awk1.xml l-awk2.xml l-awk3.xml l-redesign-1.xml l-redesign-2.xml l-redesign-3.xml l-redesign-4.xml
Date: Wed, 03 Oct 2007 17:59:46
Message-Id: E1Id8MV-0007bU-8g@stork.gentoo.org
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" ) &amp;&amp; ( $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 &amp; 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&lt;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 &lt;= 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&lt;=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 &amp; 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 &amp; 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”),文档将明确地组织成段落、章和节(使用类似于&lt;section&gt;, &lt;chapter&gt;等的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 &lt;p&gt;
1701 Yeah, sure; I got some questions:&lt;br&gt;
1702 &lt;!--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+"?&lt;br&gt;"
1708 --&gt;
1709 See, told you so.
1710 </pre>
1711
1712 <p>
1713 ……然后将它转换成:
1714 </p>
1715
1716 <pre caption="目标文档">
1717 &lt;p&gt;
1718 Yeah, sure; I got some questions:&lt;br&gt;
1719 Anyone seen bob's socks?&lt;br&gt;
1720 Anyone seen jimmy's socks?&lt;br&gt;
1721 Anyone seen ralph's socks?&lt;br&gt;
1722 Anyone seen bob's lunch?&lt;br&gt;
1723 Anyone seen jimmy's lunch?&lt;br&gt;
1724 Anyone seen ralph's lunch?&lt;br&gt;
1725 Anyone seen bob's accordion?&lt;br&gt;
1726 Anyone seen jimmy's accordion?&lt;br&gt;
1727 Anyone seen ralph's accordion?&lt;br&gt;
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&lt;len(mylines):
1756 if mylines[pos][0:8]=="&lt;!--code":
1757 mycode=""
1758 pos=pos+1
1759 while (pos&lt;len(mylines)) and (mylines[pos][0:3]!="--&gt;"):
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)&gt;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遇到以&lt;!--code开头的行,那么直到第一行以--&gt;开头的每一行的内容都会被附加到称作mycode的字符串中。然后pytext使用内置exec()函数执行mycode字符串,从而有效地创建嵌入式Python解释器。
1789 </p>
1790
1791 <p>
1792 关于这个特殊的实现,确实有一些美妙的东西──我们以这种方式调用exec(),这样会保存对全局和本地名称空间的所有修改。这样,就可以导入模块或在某嵌入块中定义变量,然后在以后创建的块中访问这个先创建的对象,如以下示例明确演示的那样:
1793 </p>
1794
1795 <pre caption="示例代码">
1796 &lt;!--code
1797 import os
1798 foo=23
1799 --&gt;
1800
1801 Hello
1802
1803 &lt;!--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 --&gt;
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}\&lt;${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" &lt;\
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 &lt;p class="note"&gt;This paragraph doesn't look so good in 4.x&lt;/p&gt;
2560 </pre>
2561
2562 <p>
2563 ……用下面的表来替换:
2564 </p>
2565
2566 <pre caption="表格样本">
2567 &lt;table width="100%" border="0" cellpadding="0" cellspacing="0"&gt;
2568 &lt;tr&gt;
2569 &lt;td bgcolor="#ddffff"&gt;&lt;p class="note"&gt;
2570 This looks a whole lot better in 4.x&lt;/p&gt;&lt;/td&gt;
2571 &lt;/tr&gt;
2572 &lt;/table&gt;
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语法要求每个文档都是单一主&lt;guide&gt;元素的一部分。为添加对主类别页面的支持,我创建了一个新的主元素:&lt;mainpage&gt;。为创建主类别页面,我将所有内容都放在&lt;mainpage&gt;元素中、而不是&lt;guide&gt;元素中,并且XSLT对输出作了适当更改。除此之外,唯一需要的重大更改是添加可选的&lt;sidebar&gt;元素,该元素用于指定主类别页面上浮动表的内容。现有的&lt;guide&gt;XSLT模板看起来类似于:
2625 </p>
2626
2627 <pre caption="XSLT模板">
2628 &lt;xsl:template match="/guide"&gt;
2629 &lt;html&gt;
2630 &lt;head&gt;
2631 guide header goes here
2632 &lt;/head&gt;
2633 &lt;body&gt;
2634 top part of guide body HTML content goes here
2635 &lt;!--next, we insert our content--&gt;
2636 &lt;xsl:apply-templates select="chapter" /&gt;
2637 bottom part of guide body HTML content goes here
2638 &lt;/body&gt;
2639 &lt;/html&gt;
2640 &lt;/xsl:template&gt;
2641 </pre>
2642
2643 <p>
2644 如果您不是很熟悉XSLT,则这个模板告诉XSLT处理程序用HTML文档的外壳替换&lt;guide&gt;&lt;/guide&gt;标记,并且将模板重复应用到&lt;guide&gt;元素内的任何&lt;chapter&gt;元素(开始/结束标记对)并将产生的结果输出插入到HTML外壳中间。
2645 </p>
2646
2647 <p>
2648 这样,为了添加对主类别页面的支持,我需要指定:如果所有内容都恰巧包括在单一&lt;mainpage&gt;元素中,应该使用一个不同的HTML外壳。要做到这点,我添加了一个新的模板,如下所示:
2649 </p>
2650
2651 <pre caption="新模板">
2652 &lt;xsl:template match="/mainpage"&gt;
2653 &lt;html&gt;
2654 &lt;head&gt;
2655 mainpage header goes here
2656 &lt;/head&gt;
2657 &lt;body&gt;
2658 top part of mainpage body HTML content goes here
2659 &lt;!--next, we insert our content--&gt;
2660 &lt;xsl:apply-templates select="chapter" /&gt;
2661 bottom part of mainpage body HTML content goes here
2662 &lt;/body&gt;
2663 &lt;/html&gt;
2664 &lt;/xsl:template&gt;
2665 </pre>
2666
2667 <p>
2668 因为几乎每一个其它的XML元素(从&lt;chapter&gt;开始之后的所有元素)都为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}\&lt;${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的简单性感到惊讶。其中,我们为&lt;changelog&gt;、&lt;entry&gt;和&lt;file&gt;指定了三个模板。我们还引用了源XML中的其它几个标记,包括&lt;date&gt;、&lt;author&gt;和&lt;msg&gt;(cvs2cl.pl使用它们来指定提交者的注释)。考虑到它大约只有35行,cvs.xsl做得已经相当多了。
2735 </p>
2736
2737 <pre caption="cvs.xsl">
2738 &lt;?xml version='1.0' encoding="iso-8859-1"?&gt;
2739 &lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
2740 &lt;xsl:output encoding="iso-8859-1" method="xml" indent="yes"/&gt;
2741 &lt;xsl:template match="/changelog"&gt;
2742 &lt;mainpage id="changelog"&gt;
2743 &lt;title&gt;Gentoo Linux Development Changelog for &lt;xsl:value-of select="entry/date"/&gt;&lt;/title&gt;
2744 &lt;author title="script"&gt;cvs-xml.xsl&lt;/author&gt;
2745 &lt;standout&gt;
2746 &lt;title&gt;About the Development Changelog&lt;/title&gt;
2747 &lt;body&gt;
2748 This page contains a daily Changelog, listing all modifications made to our
2749 CVS tree on &lt;xsl:value-of select="entry/date"/&gt; (yesterday).
2750 &lt;/body&gt;
2751 &lt;/standout&gt;
2752 &lt;version&gt;1.0.0&lt;/version&gt;
2753 &lt;date&gt;&lt;xsl:value-of select="entry/date"/&gt;&lt;/date&gt;
2754 &lt;chapter&gt;
2755 &lt;xsl:apply-templates select="entry"/&gt;
2756 &lt;/chapter&gt;
2757 &lt;/mainpage&gt;
2758 &lt;/xsl:template&gt;
2759 &lt;xsl:template match="entry"&gt;
2760 &lt;section&gt;
2761 &lt;title&gt;Files modified by &lt;xsl:value-of select="author"/&gt; at
2762 &lt;xsl:value-of select="time"/&gt;
2763 &lt;/title&gt;
2764 &lt;body&gt;
2765 &lt;note&gt;&lt;xsl:value-of select="msg"/&gt;&lt;/note&gt;
2766 &lt;ul&gt;
2767 &lt;xsl:apply-templates select="file"/&gt;
2768 &lt;/ul&gt;
2769 &lt;/body&gt;
2770 &lt;/section&gt;
2771 &lt;/xsl:template&gt;
2772 &lt;xsl:template match="file"&gt;
2773 &lt;li&gt;&lt;path&gt;&lt;xsl:value-of select="name"/&gt;&lt;/path&gt;, &lt;xsl:value-of select="revision"/&gt;&lt;/li&gt;
2774 &lt;/xsl:template&gt;
2775 &lt;/xsl:stylesheet&gt;
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