今天,在googlecode上开了个项目,关于php的,去年11月份写的xml操作类,可以使用类似jQuery的方法,操作xml,自以为还不错,发布出来共享一下。
http://phpxmlselector.googlecode.com/
Category: 没用的话
深入sql server中的事务
一. 概述... 1
二. 并发访问的不利影响... 1
1. 脏读(dirty read)... 1
2. 不可重复读(nonrepeatable read)... 1
3. 幻读(phantom read)... 1
三. 并发访问的控制机制... 2
1. 锁... 2
2. 行版本控制... 2
四. 隔离级别... 2
五. 事务... 3
1. 事务的模式... 3
1.1. 显式事务(Explicit Transactions)... 3
1.2. 自动提交事务(Autocommit Transactions)... 4
1.3. 隐式事务(Implicit Transactions)... 4
2. 事务的编程... 5
2.1. Transact-SQL脚本... 5
2.2. ADO.NET应用程序接口... 5
一. 概述
当多个用户同时访问数据库的同一资源时,叫做并发访问。如果并发的访问中有用户对数据进行修改,很可能就会对其他访问同一资源的用户产生不利的影响。可能产生的并发不利影响有以下几类:脏读、不可重复读和幻读。
为了避免并发访问产生的不利影响,sql server设计有两种并发访问的控制机制:锁、行版本控制。
二. 并发访问的不利影响
并发访问,如果没有并发访问控制机制,可能产生的不利影响有以下几种
1. 脏读(dirty read)
如果一个用户在更新一条记录,这时第二个用户来读取这条更新了的记录,但是第一个用户在更新了记录后又反悔了,不修改了,回滚了刚才的 更新。这样,导致了第二个用户实际上读取到了一条根本就没有存在过的修改后的记录。如果第一个用户在修改记录期间,把所修改的记录锁住,在修改完成前别的 用户读取不到记录,就能避免这种情况。
2. 不可重复读(nonrepeatable read)
第一个用户在一次事务中读取同一记录两次,第一次读取一条记录后,又有第二个用户来访问这条记录,并修改了这条记录,第一个用户第二次 读取这条记录时,得到的是跟第一次不同的数据了。如果第一个用户在两次读取之间锁住要读取的记录,别的用户不能去修改相应的记录就能避免这种情况。
3. 幻读(phantom read)
第一个用户在一次事务中两次读取同样满足条件的一批记录,第一次读取一批记录后,又有第二个用户来访问这个表,并在这个表中插入或者删 除了一些记录,第一个用户第二次以同样条件读取这批记录时,可能得到的结果有些记录是在第一次读取时有,第二次的结果中没有了,或者是第二次读取的结果中 有的记录在第一次读取的结果中没有的。如果第一个用户在两次读取之间锁住要读取的记录,别的用户不能去修改相应的记录,也不能增删记录,就能避免这种情 况。
三. 并发访问的控制机制
Sql server中提供了两种并发控制的机制以避免在并发访问时可能产生的不利影响。这两种机制是:
1. 锁
每个事务对所依赖的资源(如行、页或表)请求不同类型的锁。锁可以阻止其他事务以某种可能会导致事务请求锁出错的方式修改资源。当事务不再依赖锁定的资源时,它将释放锁。
根据需要锁定资源的粒度和层次,锁有许多类型,主要的有几种:
表类型:锁定整个表
行类型:锁定某个行
文件类型:锁定某个数据库文件
数据库类型:锁定整个数据库
页类型:锁定8K为单位的数据库页
锁的粒度越小,锁定的范围越小,对别的访问的阻塞就越小,但是所用的锁可能会比较多,锁的消耗就比较大。锁的粒度越大,对别的访问的阻塞可能性就越大,但是所用的锁就会比较少,锁的消耗就比较小。
对于编程人员来说,不用手工去设置控制锁,sql server通过设置事务的隔离级别自动管理锁的设置和控制。
Sql server专门管理锁的是锁管理器,锁管理器通过查询分析器分析待执行的sql语句,来判断语句将会访问哪些资源,进行什么操作,然后结合设定的隔离级别自动分配管理需要用到的锁。
2. 行版本控制
当启用了基于行版本控制的隔离级别时,数据库引擎 将维护修改的每一行的版本。应用程序可以指定事务使用行版本查看事务或查询开始时存在的数据,而不是使用锁保护所有读取。通过使用行版本控制,读取操作阻止其他事务的可能性将大大降低。
四. 隔离级别
上面提到了,sql server通过设置隔离级别来控制锁的使用,从而实现并发法访问控制。
Microsoft SQL Server 数据库引擎支持所有这些隔离级别:
l 未提交读(隔离事务的最低级别,只能保证不读取物理上损坏的数据)
l 已提交读(数据库引擎的默认级别)
l 可重复读
l 可序列化(隔离事务的最高级别,事务之间完全隔离)
这几种隔离级别,对应上面三种并发访问可能产生的不利影响,分别有不同的效果,见下表:
隔离级别 |
脏读 |
不可重复读 |
幻读 |
未提交读 |
是 |
是 |
是 |
已提交读 |
否 |
是 |
是 |
可重复读 |
否 |
否 |
是 |
快照 |
否 |
否 |
否 |
可序列化 |
否 |
否 |
否 |
五. 事务
事务是一个逻辑上的单个的工作单元,其中可以包括许多操作,但是它们在逻辑上是一个整体,要么全部完成,要么全部失败,就好像什么操作都没进行似的。
事务是十分可靠坚固的机制,它能保证事务要么全部完成,要么能全部回滚。
l 锁:使用锁的机制尽可能的保证并发事务的隔离性,避免并发的不利影响。
l 事务日志:事务日志记录着整个事务的所有操作步骤,必要的时候靠日志重新开始事务或者回滚事务。不管出现什么状况,哪怕是网络中断,机器断电,甚至是数据库引擎本身出问题了,通过事务日志都能保证事务的完整性。
l 事务管理:保证一个事务的原子性和数据的一致性。一个事务开始后,它要么成功的完成,要么失败,回滚到事务没开始前的那个状态,事务开始做的所有修改都将复原。
1. 事务的模式
控制事务的开始结束的时间点和事务的范围,有几种事务模式:
1.1.显式事务(Explicit Transactions)
显式事务通过sql脚本的BEGIN TRANSACTION或者编程接口(API)的开始事务语句启动事务,以sql脚本的COMMIT 或 ROLLBACK语句提交或回滚事务,编程接口(API)的提交事务或回滚事务语句结束事务。都是通过显式的命令控制事务的开始和结束。
从事务开始到事务提交或者回滚是一个完整的事务周期,事务一旦开始,结果要么是提交,要么是回滚。
如果事务范围内发生错误,错误分为几种类型,不同类型的错误有不同的行为。
l 严重错误
比如,客户端到服务端的网络中断了,或者客户的机器被关机了,数据引擎会被通知数据连接已中断,这样严重的错误数据引擎会自动在服务端回滚整个事务。
l 运行时错误
语句之间的“GO”命令形成的区域为命令批次。数据引擎编译和执行语句是以批次为单位的。一次编译一个批次的命令,编译完成后执行这个批次的命令。存储过程是整个被一次编译的,所以一个存储过程内不分批次,整个过程就是一个批次。
大多数情况下,在一个批次中一条语句发生运行时错误,这个语句将被中止,同时同一批次的所有后续语句也不再执行,但同一批次前面已经执行的命令依然有效。但是可以使用了try…catch捕获错误,并进行相应处理,比如执行事务回滚命令。
有一些运行时错误,比如插入了一个主键重复的记录,只中止当前出错的这条语句,后续的语句照样继续执行。这类错误也能被try…catch捕获到。
为了保证整个事务中,任何语句出现错误都回滚整个事务,最简单的方法是在事务开始前设置SET XACT_ABORT 为 ON,这个设置指示数据引擎,在一个事务中遇到一个错误后,不再执行后续的事务,并回滚整个事务。
l 编译错误
遇到编译错误时,错误语句所在的批次不被执行,并不会受SET XACT_ABORT设置的影响。
1.2.自动提交事务(Autocommit Transactions)
这个模式是数据引擎的缺省模式,也是各种编程接口的事务缺省模式。每个单独的语句在完成后被提交,失败后被回滚,编程人员不需要指定任何命令。
每个单独的语句就是一个事务的单位,成功了就提交,这句语句执行错误就回滚这条语句,对其他语句的执行不产生影响。注意这里说的执行错误是运行时错误,如果语句本身有编译错误,比如sql语句的关键词拼写错误了,那么发生编译错误语句所在的那个批次的语句都将不被执行。比如:
USE AdventureWorks;
GO CREATE TABLE TestBatch (Cola INT PRIMARY KEY, Colb CHAR(3)); GO INSERT INTO TestBatch VALUES (1, 'aaa'); INSERT INTO TestBatch VALUES (2, 'bbb'); INSERT INTO TestBatch VALUSE (3, 'ccc'); -- Syntax error. GO SELECT * FROM TestBatch; -- Returns no rows. GO |
上面这段sql中的第三个insert语句values关键字拼写错误,将导致编译错误,结果是跟这个语句在同一批次的所有三条insert语句都将不被执行。
如果上面第三个insert语句是这样的:
INSERT INTO TestBatch VALUES (1, 'ccc'); -- Duplicate key error.
这将产生一个运行时错误“重复的主键”,这条语句将被回滚,但是不影响前面两条insert语句。从这点可以看出,自动提交模式是每条单独的语句要么完成要么回滚,不影响其他语句的执行。
1.3.隐式事务(Implicit Transactions)
在SET IMPLICIT_TRANSACTIONS ON命令之后的第一条语句开始,就开始一个新的事务,直到遇到COMMIT 或 ROLLBACK语句结束这个事务,下一个语句又是一个新的事务,同样直到遇到COMMIT 或 ROLLBACK语句结束这个事务。这样形成了一个事务链,直到SET IMPLICIT_TRANSACTIONS OFF结束隐式事务,回到默认的自动提交事务模式。
事务中的行为跟显式事务模式是一致的。
事务体现在connection的水平,一个connection具有事务模式,自动提交模式是connection的缺省事务模式,直到BEGIN TRANSACTION语句开始显式事务模式,或者隐式事务被SET IMPLICIT_TRANSACTIONS ON设置,连接的事务模式被置为显式或隐式事务模式,当显示事务被提交或者回滚,隐式事务被置为关闭后,这个连接的事务模式又被置为自动提交模式。
2. 事务的编程
数据库的编程有两种方式,一种应用程序接口(API),包括ODBC、ADO 、ado.net等等编程接口,一种是Transact-SQL脚本,典型的是存储过程。
2.1.Transact-SQL脚本
BEGIN TRANSACTION
标记显式连接事务的起始点。
COMMIT TRANSACTION 或 COMMIT WORK
如果没有遇到错误,可使用该语句成功地结束事务。该事务中的所有数据修改在数据库中都将永久有效。事务占用的资源将被释放。
ROLLBACK TRANSACTION 或 ROLLBACK WORK
用来回滚遇到错误的事务。该事务修改的所有数据都返回到事务开始时的状态。事务占用的资源将被释放。
2.2.ADO.NET应用程序接口
对 SqlConnection 对象使用 BeginTransaction 方法可以启动一个显式事务。若要结束事务,可以对 SqlTransaction 对象调用 Commit() 或 Rollback() 方法。
下面主要以在存储过程中使用事务的编程详加说明
使用事务的目的是保持一段sql语句执行的完整性,要么全部执行成功,只要有一条语句失败就能完全回滚,回到事务开始前的状态。
事务有起点,即通过BEGIN TRANSACTION启动一个事务,其后执行事务中的各个语句,最后要判断,全部语句执行都成功了,就用COMMIT TRANSACTION提交事务,把事务中执行的语句的结果固定下来;如果事务中有任何错误,要能捕获到错误,并执行ROLLBACK TRANSACTION回滚整个事务。
下面是一段示例代码:
USE AdventureWorks;
BEGIN TRANSACTION; BEGIN TRY -- 产生一个违反约束的错误. DELETE FROM Production.Product WHERE ProductID = 980; END TRY BEGIN CATCH SELECT ERROR_NUMBER() AS ErrorNumber, ERROR_SEVERITY() AS ErrorSeverity, ERROR_STATE() as ErrorState, ERROR_PROCEDURE() as ErrorProcedure, ERROR_LINE() as ErrorLine, ERROR_MESSAGE() as ErrorMessage; IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; END CATCH; IF @@TRANCOUNT > 0 COMMIT TRANSACTION; |
把事务中要执行的语句都放在TRY语句块中,保证所有语句产生错误都能被捕获到。如果事务中的语句一旦产生错误,事务中的后续语句不再被执行,直接跳到CATCH语句块执行,进行出错后的后续处理过程。
CATCH语句块中的最主要的工作就是执行事务回滚语句,以回滚整个事务。也可以进行一些其他辅助性的工作,显示错误,记录错误等等。
如果事务中所有语句都没有出错,顺利执行完成,程序就跳过CATCH语句块,执行最后的COMMIT TRANSACTION提交事务。
经常看到有些人使用@@error来捕获错误,判断是否需要回滚事务,代码大概如下:
BEGIN TRANSACTION;
Select xxx from yyyy; --事务中的sql语句 …… If @@error > 0 ROLLBACK TRANSACTION; Else COMMIT TRANSACTION; |
这里使用@@error来判断事务中所有的语句是否发生错误,并以此来决定是回滚事务,还是提交事务。实际上这么做是是十分错误的。
第一,@@error是针对每个sql语句执行结果,反映的是当前执行的语句出错状态,当执行到下一句,@@error又被重置以反应下一句语句的执行结果。所以用@@error来判断所有语句是否出错是不行的。
第二,sql语句的运行时错误有两类,一类是语句发生了错误,此语句被中止,但后续语句还能被继续执行,一类是语句发生错误后,一个命令批次中的后续的所有语句也不再被执行。当事务中的语句发生这种错误,那么放在最后的If @@error > 0判断语句都不会有机会被执行了。
这样的做法可能导致很严重的后果:如果事务中有语句产生第一类的错误,后续语句都不被执行,原来设计的ROLLBACK TRANSACTION或COMMIT TRANSACTION都没有机会被执行,就是说被这个事务锁了的资源都将得不到释放,产生的后果是,如果这个事务对某些记录设置了共享锁,那这些记录再 也不能被修改,更惨的是如果这个事务对某些记录设置了排他锁,那么读取这些记录的语句一直会被堵塞,执行不下去了。程序也就死在那里了。
所以,在事务中用来捕获语句错误还是需要使用try…catch语句块。
How to choose and use source code analysis tools
January 20, 2009 (CSO) The high cost of finding and patching application flaws is well known. Wouldn't it be cheaper to write secure code in the first place?
One of the fastest growing areas in the software security industry is source code analysis tools, also known as static analysis tools. These tools review source code (or in Veracode Inc.'s case, binary code) line by line to detect security vulnerabilities and provide advice on how to remediate problems they find -- ideally before the code goes into production. (See "How to Evaluate and Use Web Application Scanners" for tools and services that search for vulnerabilities as an outside attacker might.)
The entire software security market was worth about $300 million in 2007, according to Gary McGraw, chief technology officer at Cigital Inc., a software security and quality consulting firm in Dulles, Va. McGraw estimates that the tools portion of that market doubled from 2006 to 2007 to about $180 million. About half of that is attributable to static analysis tools, which amounted to about $91.9 million, he says.
And no wonder; according to Gartner Inc., close to 90% of software attacks are aimed at the application layer. If security were integrated earlier in the software development life cycle, flaws would be uncovered earlier, reducing costs and increasing efficiency compared with removing defects later through patches or never finding them at all, says Diane Kelley, founder of SecurityCurve, a security consultancy in Amherst, N.H. "Although there is no replacement for security-aware design and a methodical approach to creating more-secure applications, code-scanning tools are a very useful addition to the process," she says.
Despite the high degree of awareness, many companies are behind the curve in their use of static analysis tools, Kelley says, possibly because of the big process changes that these tools entail.
Key decisions in source code analysis
1. Should you start with static tools or dynamic tools, or use both?
In addition to static analysis, which reviews code before it goes live, there are also dynamic analysis tools, which conduct automated scans of production Web applications to unearth vulnerabilities. In other words, dynamic tools test from the outside in, while static tools test from the inside out, says Neil McDonald, an analyst at Gartner.
Many organizations start with dynamic testing, just to get a quick assessment of where their applications stand, McDonald says. In some cases, the groups that start this initiative are in security or audit compliance departments and don't have access to source code. The natural second step is to follow up with static analyzers, enabling developers to fix the problems found by dynamic analysis tools. Some companies continue using both because each type yields different findings.
An important differentiator between the two types is that static analyzers provide the exact line of code causing the problem, while dynamic analyzers just identify the Web page causing the issue. That's why some vendors offer integration between the two types of tools.
Dynamic assessment tools "tend to be brute force," according to the chief scientist at a large software vendor who asked not to be identified. "You have to hit every parameter to find the vulnerabilities, whereas static tools investigate the whole landscape of the application." He recently chose a code scanner from Ounce Labs Inc. after outsourcing the work to Cigital since 2006. He became interested in application security when customers began requiring PCI DSS certification. He plans to add in dynamic testing in the future, but the static analysis tool is the cornerstone of his application security program.
2. Do you have the source code?
Most static analyzers scan source code, but what happens if you want to analyze third-party software or code written so long ago that you only have the executable? In that case, Veracode offers binary code scanning through a software-as-a-service system. "A vendor may not be willing to give you source code, but they will give you executables or binary," Kelley says.
At the Federal Aviation Administration, Michael Brown, director of the Office of Information Systems Security, says he chose to use Veracode's services this year because of the amount of vendor-written code the FAA anticipated to use as a result of its modernization of the national airspace system. Brown says he wanted to ensure that the code was not only functionally correct and of high quality but also secure. He wanted a service rather than a tool to reduce the need for training. So far, the results have been eye-opening, he says. "A lot of the code didn't really take security into account," he says. "There were cases of memory leaks, cross-site scripting and buffer overflows that could have been a cause for concern."
3. What do you currently use for software quality?
Some tool vendors, such as Coverity, Klocwork, Parasoft and Compuware, originated in the quality-testing arena and have added security capabilities, as opposed to vendors like Ounce and Fortify Software Inc., whose tools were solely designed for security. It's worthwhile to check into the quality tools you already use to see if you can leverage the existing relationship and tool familiarity. You should also consider whether it's important to your organization to have the two functions merged into one tool in the long term, McDonald says. (See "Penetration Testing: Dead in 2009?" for more on the interplay of quality assurance and vulnerability detection.)
Source code analysis tools: Evaluation criteria
- Support for the programming languages you use. Some companies support mobile devices, while others concentrate on enterprise languages such as Java, .Net, C, C++ and even Cobol.
- Good bug-finding performance, using a proof-of-concept assessment. Hint: Use an older build of code you had issues with and see how well the product catches bugs you had to find manually. Look for both thoroughness and accuracy. Fewer false positives means less manual work.
- Internal knowledge bases that provide descriptions of vulnerabilities and remediation information. Test for easy access and cross-referencing to discovered findings.
- Tight integration with your development platforms. Long-term, you'll likely want developers to incorporate security analysis into their daily routines.
- A robust finding/suppression mechanism to prevent false positives from reoccurring once you've verified them as a non-issue.
- The ability to easily define additional rules so the tool can enforce internal coding policies.
- A centralized reporting component if you have a large team of developers and managers who want access to findings, trending and overview reporting.
Do's and don'ts of source code analysis
Don't underestimate the adoption time required. Most static analysis projects are initiated by security or compliance staffers, not developers, who may not immediately embrace these tools. Before developers get involved, McDonald suggests doing the legwork on new processes, planning integration with other workflows like bug-tracking systems and development environments, and tuning the tool to your unique coding needs. "Don't deploy to every developer at once," he adds. "Ideally, you'll get someone who wants to take on a competency role for security testing."
The chief scientist at the large software vendor has developed an application security-awareness program that includes training on common vulnerabilities through podcasts and videocasts. Once he builds up awareness, he plans to educate developers on secure coding standards. To complete the circle, he'll introduce Ounce's static code analysis tool to enforce the standards and catch vulnerabilities "so it's a feedback loop," he says. (See "Rob Cheyne Pushes for Developer Security Awareness" for a look at a similar agenda.
Do consider using more than one tool. Collin Park, a senior engineer at NetApp Inc., says the company uses two code-analysis tools: Developers run Lint on their desktops, and the company uses Coverity each night to scan all completed code. "They catch different things," he explains. NetApp began using these tools when its customer base shifted to enterprise customers that had more stringent requirements. While Coverity is better at spotting vulnerabilities such as memory leaks, Lint catches careless coding errors that developers make and seems to run faster on developer desktops, Park says.
According to Kelley, organizations typically implement static analyzers at two stages of the development process: within the development environment, so developers can check their own code as they're writing, and within the code repository, so it can be analyzed at check-in time. The chief scientist uses this method. "In the first scan, if the engineer takes every finding and suppresses them, a milestone scan will catch those and generate a report," he says.
Do analyze pricing. Vendors have different pricing strategies, McDonald says. For instance, while all continuously add information to their libraries about the latest vulnerabilities, some charge extra for this, while others include it in the maintenance fee, he says. In addition, some vendors charge per seat, which can get expensive for large shops and may even seem wasteful for companies that don't intend to run the scanner every day. Other vendors charge per enterprise license. In addition, some vendors charge for additional languages, while others charge one price for any language they support, McDonald says.
Do plan to amend your processes. Tools are no replacement for strong processes that ensure application security from the beginning, starting with defining requirements, which should focus on security as much as functionality, according to Kelley. For instance, a tool won't tell you whether a piece of data should be encrypted to comply with the Payment Card Industry Data Security Standard. "If a company just goes out and buys one of these tools and continues to do everything else the same, they won't get to the next level," she says.
The chief scientist says it's also important to determine what will happen when vulnerabilities are found, especially because the tools can generate thousands of findings. "Does the workflow allow them to effectively analyze, triage, prioritize or dispose of the findings?" he notes. He is working with Ounce to integrate the system better with his current bug-tracking system, which is Quality Center. "It would be great to right-click on the finding to automatically inject it into the bug-tracking system," he says.
At NetApp, Park has reworked processes to ensure developers fix flagged vulnerabilities. As part of submitting code, developers do a test build, which must succeed, or it can't be checked in. Then, when they check in code, an automated process starts an incremental build. If that build fails, a bug report is filed, complete with the names of developers who checked in code before the last build. "Developers are trained to treat a build failure as something they have to look at now,'" Park says.
NetApp also created a Web-based chart that's automatically updated each night to track which managers have teams that were issued Lint or Coverity warnings and whether they were cleared.
Do retain the human element. While the tools will provide long lists of vulnerabilities, it takes a skilled professional to interpret and prioritize the results. "Companies don't have time to fix every problem, and they may not need to," Kelley says. "You have to have someone who understands what is and is not acceptable, especially in terms of a time-vs.-perfection trade-off.'"
The chief scientist calls this "truly an art form" that requires a competent security engineer. "When the tool gives you 10,000 findings, you don't want someone trying to fix all those," he says. "In fact, 10,000 may turn out to just be 500 or 100 vulnerabilities,"
Park points out an instance when the Coverity tool once found what it called "a likely infinite loop." On first glance, the developer could see there was no loop, but after a few more minutes of review, he detected something else wrong with the code. "The fact that you get the tool to stop complaining is not an indication you've fixed anything," he says.
Don't anticipate a short scan. NetApp runs scans each night, and because it needs to cover thousands of files and millions of lines of code, it takes roughly 10 hours to complete a code review. The rule of thumb, according to Coverity, is for each hour of build time, allow for two hours for the analysis to be complete. Coverity also enables companies to do incremental runs so that users don't have to scan the entire code base but just what they've changed in the nightly build.
Do consider reporting flexibility. At the FAA, Brown gets two reports: an executive summary that provides a high-level view of vulnerabilities detected and even provides a security "score," and a more detailed report that pinpoints which lines of code look troublesome and the vulnerability that was detected. In the future, Brown would like to build into vendor contracts the requirement that they meet a certain security score for all code they develop for the FAA.
Don't forget the business case. When Brown first wanted to start reviewing code, he met with some resistance from managers who wanted a defined business need. "You've got program managers with schedules to meet, and they can view this as just another bump in the road that's going to keep them from making their milestones," he says.
Brown created the business case by looking to independent sources such as Gartner and Burton Group for facts and figures about code vulnerability, and he also ran some reports on how much time the FAA was dedicating to patch management.
The chief scientist justified the cost of the Ounce tool by taking the total cost of the product and comparing that with the effort involved in a manual review. "With millions of lines of code, imagine how many engineers it would take to do that -- and, by the way, we want to do it every week," he says. "The engineers would fall down dead of boredom."
Mary Brandel is a freelance writer based outside of Boston.
[转]国际:写出漂亮代码的七种方法
首先我想说明我本文阐述的是纯粹从美学的角度来写出代码,而非技术、逻辑等。以下为写出漂亮代码的七种方法:
1, 尽快结束 if语句
例如下面这个JavaScript语句,看起来就很恐怖:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function findShape(flags, point, attribute, list) { if(!findShapePoints(flags, point, attribute)) { if(!doFindShapePoints(flags, point, attribute)) { if(!findInShape(flags, point, attribute)) { if(!findFromGuide(flags,point) { if(list.count() > 0 && flags == 1) { doSomething(); } } } } } } |
但如果这么写就好看得多:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
function findShape(flags, point, attribute, list) { if(findShapePoints(flags, point, attribute)) { return; } if(doFindShapePoints(flags, point, attribute)) { return; } if(findInShape(flags, point, attribute)) { return; } if(findFromGuide(flags,point) { return; } if (!(list.count() > 0 && flags == 1)) { return; } doSomething(); } |
你可能会很不喜欢第二种的表述方式,但反映出了迅速返回if值的思想,也可以理解为:避免不必要的else陈述。
2, 如果只是简单的布尔运算(逻辑运算),不要使用if语句
例如:
1 2 3 4 5 6 7 8 |
function isStringEmpty(str){ if(str === "") { return true; } else { return false; } } |
可以写为:
1 2 3 |
function isStringEmpty(str){ return (str === ""); } |
3, 使用空白,这是免费的
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function getSomeAngle() { // Some code here then radAngle1 = Math.atan(slope(center, point1)); radAngle2 = Math.atan(slope(center, point2)); firstAngle = getStartAngle(radAngle1, point1, center); secondAngle = getStartAngle(radAngle2, point2, center); radAngle1 = degreesToRadians(firstAngle); radAngle2 = degreesToRadians(secondAngle); baseRadius = distance(point, center); radius = baseRadius + (lines * y); p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]); p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]); pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]); pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y"); // Now some more code } |
很多开发者不愿意使用空白,就好像这要收费一样。我在此并非刻意地添加空白,粗鲁地打断代码的连贯性。在实际编写代码的过程中,会很容易地发现在什么地方加入空白,这不但美观而且让读者易懂,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function getSomeAngle() { // Some code here then radAngle1 = Math.atan(slope(center, point1)); radAngle2 = Math.atan(slope(center, point2)); firstAngle = getStartAngle(radAngle1, point1, center); secondAngle = getStartAngle(radAngle2, point2, center); radAngle1 = degreesToRadians(firstAngle); radAngle2 = degreesToRadians(secondAngle); baseRadius = distance(point, center); radius = baseRadius + (lines * y); p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]); p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]); pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]); pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y"); // Now some more code } |
4, 不要使用无谓的注释
无谓的注释让人费神,这实在很讨厌。不要标出很明显的注释。在以下的例子中,每个人都知道代码表达的是“students id”,因而没必要标出。
1 2 3 4 5 6 7 8 9 10 11 |
function existsStudent(id, list) { for(i = 0; i < list.length; i++) { student = list[i]; // Get the student's id thisId = student.getId(); if(thisId === id) { return true; } } return false; } |
5, 不要在源文件中留下已经删除的代码,哪怕你标注了
如果你使用了版本控制,那么你就可以轻松地找回前一个版本的代码。如果别人大费周折地读了你的代码,却发现是要删除的代码,这实在太恨人了。
1 2 3 4 5 6 |
//function thisReallyHandyFunction() { // someMagic(); // someMoreMagic(); // magicNumber = evenMoreMagic(); // return magicNumber; //} |
6,不要有太长的代码
看太长的代码实在太费劲,尤其是代码本身的功能又很小。如下:
1 2 3 4 5 |
public static EnumMap<category, IntPair> getGroupCategoryDistribution(EnumMap<category, Integer> sizes, int groups) { EnumMap<category, IntPair> categoryGroupCounts = new EnumMap<category,IntPair>(Category.class); for(Category cat : Category.values()) { categoryGroupCounts.put(cat, getCategoryDistribution(sizes.get(cat), groups)); } |
#
我并不是说非要坚持70个字符以内,但是一个比较理想的长度是控制在120个字符内。如果你把代码发布在互联网上,用户读起来就很困难。
7,不要在一个功能(或者函数内)有太多代码行
我的一个老同事曾经说Visual C++很臭,因为它不允许你在一个函数内拥有超过10,000行代码。我记不清代码行数的上限,不知道他说的是否正确,但我很不赞成他的观点。如果一个函数超过了50行,看起来有多费劲你知道么,还有没完没了的if循环,而且你还的滚动鼠标前后对照这段代码。对我而言,超过35行的代码理解起来就很困难了。我的建议是超过这个数字就把一个函数代码分割成两个。
转自:http://news.csdn.net/n/20081217/121810.html
Taste for Makers
February 2002
|
I was talking recently to a friend who teaches at MIT. His field is hot now and every year he is inundated by applications from would-be graduate students. "A lot of them seem smart," he said. "What I can't tell is whether they have any kind of taste."
Taste. You don't hear that word much now. And yet we still need the underlying concept, whatever we call it. What my friend meant was that he wanted students who were not just good technicians, but who could use their technical knowledge to design beautiful things.
Mathematicians call good work "beautiful," and so, either now or in the past, have scientists, engineers, musicians, architects, designers, writers, and painters. Is it just a coincidence that they used the same word, or is there some overlap in what they meant? If there is an overlap, can we use one field's discoveries about beauty to help us in another?
For those of us who design things, these are not just theoretical questions. If there is such a thing as beauty, we need to be able to recognize it. We need good taste to make good things. Instead of treating beauty as an airy abstraction, to be either blathered about or avoided depending on how one feels about airy abstractions, let's try considering it as a practical question: how do you make good stuff?
If you mention taste nowadays, a lot of people will tell you that "taste is subjective." They believe this because it really feels that way to them. When they like something, they have no idea why. It could be because it's beautiful, or because their mother had one, or because they saw a movie star with one in a magazine, or because they know it's expensive. Their thoughts are a tangle of unexamined impulses.
Most of us are encouraged, as children, to leave this tangle unexamined. If you make fun of your little brother for coloring people green in his coloring book, your mother is likely to tell you something like "you like to do it your way and he likes to do it his way."
Your mother at this point is not trying to teach you important truths about aesthetics. She's trying to get the two of you to stop bickering.
Like many of the half-truths adults tell us, this one contradicts other things they tell us. After dinning into you that taste is merely a matter of personal preference, they take you to the museum and tell you that you should pay attention because Leonardo is a great artist.
What goes through the kid's head at this point? What does he think "great artist" means? After having been told for years that everyone just likes to do things their own way, he is unlikely to head straight for the conclusion that a great artist is someone whose work is better than the others'. A far more likely theory, in his Ptolemaic model of the universe, is that a great artist is something that's good for you, like broccoli, because someone said so in a book.
Saying that taste is just personal preference is a good way to prevent disputes. The trouble is, it's not true. You feel this when you start to design things.
Whatever job people do, they naturally want to do better. Football players like to win games. CEOs like to increase earnings. It's a matter of pride, and a real pleasure, to get better at your job. But if your job is to design things, and there is no such thing as beauty, then there is no way to get better at your job. If taste is just personal preference, then everyone's is already perfect: you like whatever you like, and that's it.
As in any job, as you continue to design things, you'll get better at it. Your tastes will change. And, like anyone who gets better at their job, you'll know you're getting better. If so, your old tastes were not merely different, but worse. Poof goes the axiom that taste can't be wrong.
Relativism is fashionable at the moment, and that may hamper you from thinking about taste, even as yours grows. But if you come out of the closet and admit, at least to yourself, that there is such a thing as good and bad design, then you can start to study good design in detail. How has your taste changed? When you made mistakes, what caused you to make them? What have other people learned about design?
Once you start to examine the question, it's surprising how much different fields' ideas of beauty have in common. The same principles of good design crop up again and again.
Good design is simple. You hear this from math to painting. In math it means that a shorter proof tends to be a better one. Where axioms are concerned, especially, less is more. It means much the same thing in programming. For architects and designers it means that beauty should depend on a few carefully chosen structural elements rather than a profusion of superficial ornament. (Ornament is not in itself bad, only when it's camouflage on insipid form.) Similarly, in painting, a still life of a few carefully observed and solidly modelled objects will tend to be more interesting than a stretch of flashy but mindlessly repetitive painting of, say, a lace collar. In writing it means: say what you mean and say it briefly.
It seems strange to have to emphasize simplicity. You'd think simple would be the default. Ornate is more work. But something seems to come over people when they try to be creative. Beginning writers adopt a pompous tone that doesn't sound anything like the way they speak. Designers trying to be artistic resort to swooshes and curlicues. Painters discover that they're expressionists. It's all evasion. Underneath the long words or the "expressive" brush strokes, there is not much going on, and that's frightening.
When you're forced to be simple, you're forced to face the real problem. When you can't deliver ornament, you have to deliver substance.
Good design is timeless. In math, every proof is timeless unless it contains a mistake. So what does Hardy mean when he says there is no permanent place for ugly mathematics? He means the same thing Kelly Johnson did: if something is ugly, it can't be the best solution. There must be a better one, and eventually someone will discover it.
Aiming at timelessness is a way to make yourself find the best answer: if you can imagine someone surpassing you, you should do it yourself. Some of the greatest masters did this so well that they left little room for those who came after. Every engraver since Durer has had to live in his shadow.
Aiming at timelessness is also a way to evade the grip of fashion. Fashions almost by definition change with time, so if you can make something that will still look good far into the future, then its appeal must derive more from merit and less from fashion.
Strangely enough, if you want to make something that will appeal to future generations, one way to do it is to try to appeal to past generations. It's hard to guess what the future will be like, but we can be sure it will be like the past in caring nothing for present fashions. So if you can make something that appeals to people today and would also have appealed to people in 1500, there is a good chance it will appeal to people in 2500.
Good design solves the right problem. The typical stove has four burners arranged in a square, and a dial to control each. How do you arrange the dials? The simplest answer is to put them in a row. But this is a simple answer to the wrong question. The dials are for humans to use, and if you put them in a row, the unlucky human will have to stop and think each time about which dial matches which burner. Better to arrange the dials in a square like the burners.
A lot of bad design is industrious, but misguided. In the mid twentieth century there was a vogue for setting text in sans-serif fonts. These fonts are closer to the pure, underlying letterforms. But in text that's not the problem you're trying to solve. For legibility it's more important that letters be easy to tell apart. It may look Victorian, but a Times Roman lowercase g is easy to tell from a lowercase y.
Problems can be improved as well as solutions. In software, an intractable problem can usually be replaced by an equivalent one that's easy to solve. Physics progressed faster as the problem became predicting observable behavior, instead of reconciling it with scripture.
Good design is suggestive. Jane Austen's novels contain almost no description; instead of telling you how everything looks, she tells her story so well that you envision the scene for yourself. Likewise, a painting that suggests is usually more engaging than one that tells. Everyone makes up their own story about the Mona Lisa.
In architecture and design, this principle means that a building or object should let you use it how you want: a good building, for example, will serve as a backdrop for whatever life people want to lead in it, instead of making them live as if they were executing a program written by the architect.
In software, it means you should give users a few basic elements that they can combine as they wish, like Lego. In math it means a proof that becomes the basis for a lot of new work is preferable to a proof that was difficult, but doesn't lead to future discoveries; in the sciences generally, citation is considered a rough indicator of merit.
Good design is often slightly funny. This one may not always be true. But Durer's engravings and Saarinen's womb chair and the Pantheon and the original Porsche 911 all seem to me slightly funny. Godel's incompleteness theorem seems like a practical joke.
I think it's because humor is related to strength. To have a sense of humor is to be strong: to keep one's sense of humor is to shrug off misfortunes, and to lose one's sense of humor is to be wounded by them. And so the mark-- or at least the prerogative-- of strength is not to take oneself too seriously. The confident will often, like swallows, seem to be making fun of the whole process slightly, as Hitchcock does in his films or Bruegel in his paintings-- or Shakespeare, for that matter.
Good design may not have to be funny, but it's hard to imagine something that could be called humorless also being good design.
Good design is hard. If you look at the people who've done great work, one thing they all seem to have in common is that they worked very hard. If you're not working hard, you're probably wasting your time.
Hard problems call for great efforts. In math, difficult proofs require ingenious solutions, and those tend to be interesting. Ditto in engineering.
When you have to climb a mountain you toss everything unnecessary out of your pack. And so an architect who has to build on a difficult site, or a small budget, will find that he is forced to produce an elegant design. Fashions and flourishes get knocked aside by the difficult business of solving the problem at all.
Not every kind of hard is good. There is good pain and bad pain. You want the kind of pain you get from going running, not the kind you get from stepping on a nail. A difficult problem could be good for a designer, but a fickle client or unreliable materials would not be.
In art, the highest place has traditionally been given to paintings of people. There is something to this tradition, and not just because pictures of faces get to press buttons in our brains that other pictures don't. We are so good at looking at faces that we force anyone who draws them to work hard to satisfy us. If you draw a tree and you change the angle of a branch five degrees, no one will know. When you change the angle of someone's eye five degrees, people notice.
When Bauhaus designers adopted Sullivan's "form follows function," what they meant was, form should follow function. And if function is hard enough, form is forced to follow it, because there is no effort to spare for error. Wild animals are beautiful because they have hard lives.
Good design looks easy. Like great athletes, great designers make it look easy. Mostly this is an illusion. The easy, conversational tone of good writing comes only on the eighth rewrite.
In science and engineering, some of the greatest discoveries seem so simple that you say to yourself, I could have thought of that. The discoverer is entitled to reply, why didn't you?
Some Leonardo heads are just a few lines. You look at them and you think, all you have to do is get eight or ten lines in the right place and you've made this beautiful portrait. Well, yes, but you have to get them in exactly the right place. The slightest error will make the whole thing collapse.
Line drawings are in fact the most difficult visual medium, because they demand near perfection. In math terms, they are a closed-form solution; lesser artists literally solve the same problems by successive approximation. One of the reasons kids give up drawing at ten or so is that they decide to start drawing like grownups, and one of the first things they try is a line drawing of a face. Smack!
In most fields the appearance of ease seems to come with practice. Perhaps what practice does is train your unconscious mind to handle tasks that used to require conscious thought. In some cases you literally train your body. An expert pianist can play notes faster than the brain can send signals to his hand. Likewise an artist, after a while, can make visual perception flow in through his eye and out through his hand as automatically as someone tapping his foot to a beat.
When people talk about being in "the zone," I think what they mean is that the spinal cord has the situation under control. Your spinal cord is less hesitant, and it frees conscious thought for the hard problems.
Good design uses symmetry. I think symmetry may just be one way to achieve simplicity, but it's important enough to be mentioned on its own. Nature uses it a lot, which is a good sign.
There are two kinds of symmetry, repetition and recursion. Recursion means repetition in subelements, like the pattern of veins in a leaf.
Symmetry is unfashionable in some fields now, in reaction to excesses in the past. Architects started consciously making buildings asymmetric in Victorian times and by the 1920s asymmetry was an explicit premise of modernist architecture. Even these buildings only tended to be asymmetric about major axes, though; there were hundreds of minor symmetries.
In writing you find symmetry at every level, from the phrases in a sentence to the plot of a novel. You find the same in music and art. Mosaics (and some Cezannes) get extra visual punch by making the whole picture out of the same atoms. Compositional symmetry yields some of the most memorable paintings, especially when two halves react to one another, as in the Creation of Adam or American Gothic.
In math and engineering, recursion, especially, is a big win. Inductive proofs are wonderfully short. In software, a problem that can be solved by recursion is nearly always best solved that way. The Eiffel Tower looks striking partly because it is a recursive solution, a tower on a tower.
The danger of symmetry, and repetition especially, is that it can be used as a substitute for thought.
Good design resembles nature. It's not so much that resembling nature is intrinsically good as that nature has had a long time to work on the problem. It's a good sign when your answer resembles nature's.
It's not cheating to copy. Few would deny that a story should be like life. Working from life is a valuable tool in painting too, though its role has often been misunderstood. The aim is not simply to make a record. The point of painting from life is that it gives your mind something to chew on: when your eyes are looking at something, your hand will do more interesting work.
Imitating nature also works in engineering. Boats have long had spines and ribs like an animal's ribcage. In some cases we may have to wait for better technology: early aircraft designers were mistaken to design aircraft that looked like birds, because they didn't have materials or power sources light enough (the Wrights' engine weighed 152 lbs. and generated only 12 hp.) or control systems sophisticated enough for machines that flew like birds, but I could imagine little unmanned reconnaissance planes flying like birds in fifty years.
Now that we have enough computer power, we can imitate nature's method as well as its results. Genetic algorithms may let us create things too complex to design in the ordinary sense.
Good design is redesign. It's rare to get things right the first time. Experts expect to throw away some early work. They plan for plans to change.
It takes confidence to throw work away. You have to be able to think, there's more where that came from. When people first start drawing, for example, they're often reluctant to redo parts that aren't right; they feel they've been lucky to get that far, and if they try to redo something, it will turn out worse. Instead they convince themselves that the drawing is not that bad, really-- in fact, maybe they meant it to look that way.
Dangerous territory, that; if anything you should cultivate dissatisfaction. In Leonardo's drawings there are often five or six attempts to get a line right. The distinctive back of the Porsche 911 only appeared in the redesign of an awkward prototype. In Wright's early plans for the Guggenheim, the right half was a ziggurat; he inverted it to get the present shape.
Mistakes are natural. Instead of treating them as disasters, make them easy to acknowledge and easy to fix. Leonardo more or less invented the sketch, as a way to make drawing bear a greater weight of exploration. Open-source software has fewer bugs because it admits the possibility of bugs.
It helps to have a medium that makes change easy. When oil paint replaced tempera in the fifteenth century, it helped painters to deal with difficult subjects like the human figure because, unlike tempera, oil can be blended and overpainted.
Good design can copy. Attitudes to copying often make a round trip. A novice imitates without knowing it; next he tries consciously to be original; finally, he decides it's more important to be right than original.
Unknowing imitation is almost a recipe for bad design. If you don't know where your ideas are coming from, you're probably imitating an imitator. Raphael so pervaded mid-nineteenth century taste that almost anyone who tried to draw was imitating him, often at several removes. It was this, more than Raphael's own work, that bothered the Pre-Raphaelites.
The ambitious are not content to imitate. The second phase in the growth of taste is a conscious attempt at originality.
I think the greatest masters go on to achieve a kind of selflessness. They just want to get the right answer, and if part of the right answer has already been discovered by someone else, that's no reason not to use it. They're confident enough to take from anyone without feeling that their own vision will be lost in the process.
Good design is often strange. Some of the very best work has an uncanny quality: Euler's Formula, Bruegel's Hunters in the Snow, the SR-71, Lisp. They're not just beautiful, but strangely beautiful.
I'm not sure why. It may just be my own stupidity. A can-opener must seem miraculous to a dog. Maybe if I were smart enough it would seem the most natural thing in the world that ei*pi = -1. It is after all necessarily true.
Most of the qualities I've mentioned are things that can be cultivated, but I don't think it works to cultivate strangeness. The best you can do is not squash it if it starts to appear. Einstein didn't try to make relativity strange. He tried to make it true, and the truth turned out to be strange.
At an art school where I once studied, the students wanted most of all to develop a personal style. But if you just try to make good things, you'll inevitably do it in a distinctive way, just as each person walks in a distinctive way. Michelangelo was not trying to paint like Michelangelo. He was just trying to paint well; he couldn't help painting like Michelangelo.
The only style worth having is the one you can't help. And this is especially true for strangeness. There is no shortcut to it. The Northwest Passage that the Mannerists, the Romantics, and two generations of American high school students have searched for does not seem to exist. The only way to get there is to go through good and come out the other side.
Good design happens in chunks. The inhabitants of fifteenth century Florence included Brunelleschi, Ghiberti, Donatello, Masaccio, Filippo Lippi, Fra Angelico, Verrocchio, Botticelli, Leonardo, and Michelangelo. Milan at the time was as big as Florence. How many fifteenth century Milanese artists can you name?
Something was happening in Florence in the fifteenth century. And it can't have been heredity, because it isn't happening now. You have to assume that whatever inborn ability Leonardo and Michelangelo had, there were people born in Milan with just as much. What happened to the Milanese Leonardo?
There are roughly a thousand times as many people alive in the US right now as lived in Florence during the fifteenth century. A thousand Leonardos and a thousand Michelangelos walk among us. If DNA ruled, we should be greeted daily by artistic marvels. We aren't, and the reason is that to make Leonardo you need more than his innate ability. You also need Florence in 1450.
Nothing is more powerful than a community of talented people working on related problems. Genes count for little by comparison: being a genetic Leonardo was not enough to compensate for having been born near Milan instead of Florence. Today we move around more, but great work still comes disproportionately from a few hotspots: the Bauhaus, the Manhattan Project, the New Yorker, Lockheed's Skunk Works, Xerox Parc.
At any given time there are a few hot topics and a few groups doing great work on them, and it's nearly impossible to do good work yourself if you're too far removed from one of these centers. You can push or pull these trends to some extent, but you can't break away from them. (Maybe you can, but the Milanese Leonardo couldn't.)
Good design is often daring. At every period of history, people have believed things that were just ridiculous, and believed them so strongly that you risked ostracism or even violence by saying otherwise.
If our own time were any different, that would be remarkable. As far as I can tell it isn't.
This problem afflicts not just every era, but in some degree every field. Much Renaissance art was in its time considered shockingly secular: according to Vasari, Botticelli repented and gave up painting, and Fra Bartolommeo and Lorenzo di Credi actually burned some of their work. Einstein's theory of relativity offended many contemporary physicists, and was not fully accepted for decades-- in France, not until the 1950s.
Today's experimental error is tomorrow's new theory. If you want to discover great new things, then instead of turning a blind eye to the places where conventional wisdom and truth don't quite meet, you should pay particular attention to them.
As a practical matter, I think it's easier to see ugliness than to imagine beauty. Most of the people who've made beautiful things seem to have done it by fixing something that they thought ugly. Great work usually seems to happen because someone sees something and thinks, I could do better than that. Giotto saw traditional Byzantine madonnas painted according to a formula that had satisfied everyone for centuries, and to him they looked wooden and unnatural. Copernicus was so troubled by a hack that all his contemporaries could tolerate that he felt there must be a better solution.
Intolerance for ugliness is not in itself enough. You have to understand a field well before you develop a good nose for what needs fixing. You have to do your homework. But as you become expert in a field, you'll start to hear little voices saying, What a hack! There must be a better way. Don't ignore those voices. Cultivate them. The recipe for great work is: very exacting taste, plus the ability to gratify it.
Notes
Sullivan actually said "form ever follows function," but I think the usual misquotation is closer to what modernist architects meant.
Stephen G. Brush, "Why was Relativity Accepted?" Phys. Perspect. 1 (1999) 184-214.
[转]创造者的鉴赏力
<版权信息>
在保留和不改变本版权信息的前提下, 本译文可以自由地复制,变更和再发布.
Copyright 2002 by Paul Graham
原文: http://www.paulgraham.com/taste.html
中文译者: 戴雨文
<版权信息结束>
- Thomas Kuhn, The Copernican Revolution
"在Kelly Johnson的训练之下,我们狂热地坚信他的主张: 一架看上去很美的飞机飞得也会同样的美."
- Ben Rich, Skunk Works
"美是第一道检验: 世上没有永久的地方容纳丑陋的数学."
- G. H. Hardy, A Mathematician's Apology
我最近与一位在MIT任教的朋友聊天. 他的领域现在很热门,来自即将成为研究生的申请表每年都潮水般地涌向他. "他们中的大多数看上去都很聪明,"他说. "我不能确定的是他们是否有鉴赏力."
鉴赏力. 你现在不常听到这个词了. 不过我们仍然需要其中的概念,不管人们叫它什么. 我朋友的意思是,他希望学生不仅是好的技术人员, 而且会用他们的技术知识设计出美好的事物.
数学家称出色的工作是"美的", 就象不论是过去还是现在,科学家,工程师,音乐家,建筑师,设计师,作家和画家用"美"来形容作品一样. 他们使用同一个形容词,是一种巧合,还是他们所说的有某种含义上的重合? 如果有重合, 我们能否利用一个领域里关于美的发现,去找到另一个领域(的美)?
对于我们设计者来说,这些不仅是理论问题. 如果的确有叫做美的东西,我们必须能够认识它. 我们需要好的鉴赏力来做出好的事物. 与其视美为空洞的抽象物, 我们不如把它看成一个实际的问题: 你如何做出好的物品?
如果你现在提起鉴赏力, 许多人会告诉你"鉴赏力是主观的". 他们实际上是这样感觉的,所以他们这样认为. 当他们喜欢某样东西的时候,也不知道是为什么. 可能是因为它美,也可能是他们的妈妈有同样的东西,或者是在杂志上看到某个电影明星有同样的东西,或者他们知道这东西很昂贵. 他们的思维处于未经权衡的随心所欲的混乱状态.
大多数人从小就被鼓励让这种随心所欲处在未经权衡的状态下. 如果你取笑你的弟弟在图画书上把人的皮肤涂成绿色, 你妈妈可能会说"你喜欢你的方式,他喜欢他的方式"之类的话.
你妈妈这时并不是想教你重要的美学理论,她只不过想让你俩停止斗嘴.
就象成人告诉我们的许多半真半假的事一样, 这件事与他们说的其它的事矛盾. 再三地跟你说了"鉴赏力只不过是个人的喜好"之后, 他们带你去了博物馆, 并告诉你,你得用点心, 因为达芬奇是一个伟大的艺术家.
这时闪过孩子脑海里的是什么? 他会认为"伟大的艺术家"是什么意思呢? 经过多年的"每个人喜欢用他自己的方式做事"的灌输之后,他不太可能直接得出结论:所谓伟大的艺术家,就是他的作品要比别人的好. 在他托勒密式的宇宙观里,更可能的结论是:伟大的艺术家是对你有好处的,就象书上说椰菜对人的身体有好处一样.
说鉴赏力是个人喜好是避免争论的好办法. 问题是,它不是真的. 当你开始设计事物时,你会感觉到这点.
无论人们做什么工作,他们自然地想做得好些. 足球队员想赢得比赛, CEO想增加收入. 在工作中做得更好, 使人感到愉快和骄傲. 不过如果你的工作是设计,而且其中没有美这码事, 那么就没有办法把工作做得更好. 如果鉴赏力仅是个人喜好, 那每个人都是完美的: 你无论喜欢什么都行,不必多说了.
就象任何一项工作, 当你持续地设计物体,你会得到更好的效果. 你的鉴赏力会改变. 而且就象任何在工作中越做越好的人一样,你知道你也在进步. 如果是这样的话,你原来的鉴赏力不仅和现在不同,而且比现在的坏. 让鉴赏力不会有错的公理见鬼去吧.
现在盛行的相对主义可能会妨碍你对鉴赏力的思考,即使你自己的鉴赏力正在发展. 但是如果你面对现实并承认,至少对你而言,存在着好的设计和坏的设计, 然后你可以开始仔细研究好的设计. 你的鉴赏力是如何改变的? 当你犯错误的时候,想想什么使你犯这个错误? 其他人从设计中学到了什么?
你一旦开始思索这些问题, 就会惊讶地发现美的观念在多少不同的领域是相通的. 同样的完美设计的原则一遍又一遍地出现在人们的面前.
好的设计是简单的. 从数学到绘画,你都能听到它. 在数学里它意味着一个较短的证明往往较好. 特别是公理,越少越好. 在程序设计领域,也是同样的道理. 对建筑师和设计者来说,这意味着美应该依赖于一些精心选择的结构性的元素,而不是过多的表面装饰. (装饰本身并不坏,坏在被用来掩饰平淡的实体.) 类似地, 在绘画领域, 经过仔细观察和扎实临摹的静物画往往比一幅浮华但没头脑的画(比如带花边的衣领)更令人感兴趣. 在写作领域,它意味着简洁地说出你想说的.
当你被迫做得简单,说明你正在面对实际的问题. 如果你不能放弃装饰,你就得放弃本质.
好的设计是永恒的. 数学里的每个证明都是永久的,除非它有错误. 那哈代说 "世上没有永久的地方容纳丑陋的数学"是什么意思呢? 他的意思和Kelly Johnson的一样: 丑陋的东西不可能是最好的解决办法. 一定有更好的办法,最终有人会发现它.
以永恒为目标是发现最佳答案的一个方法: 如果你能想象到别人能超过你,你还是自己来吧. 一些最伟大的大师在这方面做得如此之好,几乎没给后来者留下多少空间. 丢勒之后的雕刻师不得不生活在他的阴影下.
奇怪的是, 如果你想做出吸引将来的人类的事物,一种方法是设法吸引过去的人类. 很难猜测将来会怎样, 但我们可以肯定, 将来会象过去一样,不会关心现在的时尚. 因此如果你能做出吸引当代的人和1500年的人的东西,极有可能它会吸引2500年的人类.
好的设计解决正确的问题. 典型的(烹饪用的)炉子有四个出火口,形成一个正方形,各有一个开关控制它们. 你如何安排这些开关? 最简单的答案是把它们排成一行. 但这是答非所问. 开关是给人用的,如果你把它们排成一行,不幸的厨师不得不每次都停下来思考一下哪个开关是控制哪个出火口的. 更好的办法是象出火口那样安排成一个正方形.
许多坏的设计是勤勉的,但是被误导了. 二十世纪中叶有一股使用无衬线(sans-serif)字体的风气. 这些字体的确更接近纯粹的基本的字形. 但这不是你在文本里要解决的问题. 字母能被容易地认出是更重要的事情. 虽然象是维多利亚时代的风格, 但Times Roman的小写字母g很容易与小写字母y区分.
问题可以解决也可以改进. 在软件领域, 一个难以对付的问题通常可以被一个等价的较易解决的问题代替. 物理学因为要解决的问题变为预测可观察事物的行为,而不是把它与经典著作调和起来,而发展得更快了.
好的设计是有启发性的. 简奥斯汀的小说几乎没有描写,不是告诉你每样事物是什么样子的, 她讲故事如此之好以至于你可以自己想象出场景. 类似地, 有启发的画通常比合盘托出的画更有吸引力. 每个看过蒙娜丽莎的人都有他自己的关于她的故事.
此原则在建筑或设计界的体现是,建筑物或物体应该让你自如地使用: 比如说一幢好的建筑物,能充当这样一个背景,让住在此处的人过任何他们想过的生活, 而不是生活起居就象在执行建筑师的程序.
在软件领域,它意味着你应该给用户一些基本的元素,它们可以象拼装玩具一样自由地组合. 在数学里,它意味着一个能成为许多新工作的基础的证明比一个因难但不能引出什么新发现的证明更可取. 在科学领域,一般来说,(被别人)引用的多少是自身价值的粗略指标.
好的设计常常有点滑稽. 这点并不总是正确. 但丢勒(Durer)的雕刻, 沙里宁(Saarinen)的womb char, pantheon, 以及最初的Porsche 911在我看来都有点儿滑稽. 哥德尔的不完全定理就象一个恶作剧.
我想这是因为幽默与力量有关吧. 有幽默感就有力量: 保持幽默感就是对不幸一笑了之, 而失去幽默感就会被它伤害. 因此力量的标志,或至少是特长,是不要把事情看得太严重. 自信会你显得对全过程采取一种轻松的态度. 就象希区柯克(Hitchcock)在他的电影中, 勃鲁盖尔(Brueghel)在他的绘画中,莎士比亚(Shakespeare)在他的戏剧中所表现的一样.
好的设计不必表现得滑稽,但很难想象没有幽默感的东西会是好的设计.
好的设计是困难的. 看一下有过伟大成就的人物,有一点是共同的:他们曾经努力地工作. 如果你不努力,可能你在浪费时间.
困难的问题需要巨大的努力. 困难的数学证明需要天才的解答,而且它往往是令人着迷的. 工程界也是这样.
你爬山的时候会把所有不必要的东西从背包里拿出来. 同样一个要在困难的地点,或只有很小的预算的条件下造房的建筑师,会发现他必须做出优雅的设计. 流行和浮华的东西只能被撇在一边了.
并不是所有的努力都是好的. 苦痛也有优劣之分. 你希望那种飞奔起来的痛,而不是站在钉子上的痛, 困难的问题可能对设计师有好处, 而刁难的顾客和不可靠的原料可没什么好处.
传统上美术领域的最高位置留给了人物画. 传统是有原因的,不是因为人物画在我们头脑里留下印象,而其它画种没有. 我们是如此善于观察人脸,迫使画脸的人不懈努力使我们感到满意. 如果你画树的时候把树枝画偏了五度,没人会发现. 如果你把人眼画偏了五度, 人人都会注意到.
当Bauhaus学派采纳Sullivan的"形式跟随功能"的时候,他们指的是,形式应该跟随功能. 而且如果功能足够困难, 形式也必须跟随,因为没有出错的余地. 野生动物是美丽的,因为它们有艰苦的生活.
好的设计看上去很容易. 就象优秀的运动员,伟大的设计者使人觉得设计很容易. 通常这是一种表象. 经过好几遍的修改, 才会有读起来朗朗上口的文章.
在科技界,一些最伟大的发现看上去是如此简单,你会对自己说,我也想得到. 发现者有资格回答这个问题: 哪你为什么没有(想到)呢?
达芬奇的一些头像画仅寥寥数笔. 你注视着这些画,心里暗想,你所要做的只是把这八九条线画到正确的位置,然后一幅杰作就产生了. 是的, 但你必须把它们画到恰好正确的位置. 一点儿偏差就会让整幅画失败.
线条画要求近乎完美,因此事实上它是最难的视觉媒体. 用数学的术语说,它是封闭的解. 不那么优秀的艺术家用逐渐逼近的方法解决同样的问题. 十岁左右的孩子放弃绘画的一个原因是,他们决心象大人一样画画,而且第一次就尝试画一张人脸. 当头一棒!
在许多领域,容易是和练习联系在一起的. 也许练习训练你用潜意识来完成得用意识来完成的任务. 在一些情况下, 你精确地训练你的身体. 专业钢琴家按键快于大脑传给手的信号. 经过一段时间训练的画家,可以把视觉感知从眼传到手, 尤如条件反射.
当说一个人"进入化境"时, 我认为他们是指脊髓控制了身体,脊髓少些犹豫, 而且解放了意识,让它思考更难的问题.
好的设计使用对称. 我认为对称可能只是取得简单性的途径之一,但它很重要,值得单独提出来. 自然界大量地应用它, 这是一个好迹象.
有两类对称: 重复和递归. 递归是指在亚层次上重复,就象树叶的脉络.
对称在一些领域里不流行了,作为对以前过多使用的反弹. 建筑师在维多利亚时代开始有意识地使用不对称, 到了1920年代,不对称成为现代主义建筑的明确前提. 但即使是这类建筑也只是在中轴线上不对称,还有许多小的地方是对称的.
在写作中各个层次上都有对称,从句子中的词组到小说的结构. 音乐和绘画也是如此. 由相同颗粒组成的马赛克画(和某些塞尚的画)有特别的视觉冲击力. 组合而成的对称产生了一些最难忘的作品: 亚当的诞生和美洲哥特式教堂.
在数学和工程里递归特别有用. 归纳法惊人地简洁. 能够用递归解决的软件问题几乎肯定是最好的解决办法. 埃菲尔铁塔引人注意的部分原因是它是递归的: 一个塔叠着一个塔.
对称,尤其是重复的危险在于,它可能会代替思考.
好的设计模仿自然. 与其说模仿自然有本质上的好处,还不如说大自然已经花了亿万年的时间探索问题的解决方案. 如果你的答案模仿了自然,那是个好迹象.
复制并不是作弊. 没人会否认故事应该象生活. 从生活中找到灵感也是绘画的法宝, 虽然它的任务经常被误解. 目标是不要简单地作个记录, 要点是它给你某些值得玩味的东西: 当你的目光注视着一个物体,你的手会做出更有趣的工作.
效法自然在工程领域也是起作用的. 船很久以来就有脊骨和加强筋,好象动物的胸腔. 在某些情况下我们不得不等待更好的技术出现: 早期的飞机设计者错误地把飞机设计成鸟的样子, 但是他们没有足够轻的材料或动力(莱特兄弟的引擎重152磅,却只有12马力的输出.),也没有精巧的导航系统使得机器象鸟一样飞翔. 不过我预测小型的能象鸟一样飞行的无人驾驶飞机会在五十年内出现.
既然有了强大的计算能力,我们不但可以模仿大自然的结果,也可以模拟大自然的方法. 基因算法能让我们创造出因为太复杂而在通常条件下设计不出的东西.
好的设计是再设计. 第一次就把事情做对的可能性是很小的. 专家料到会扔掉一些初期的作品,他们为计划的改变作了计划.
把作品扔掉需要自信. 你必须这样想,会有更多的成果出现. 举个例子,人们刚开始学画的时候,不情愿重画那些不好的地方. 他们觉得做到这步已经很幸运了,如果重做的话,可能会更糟. 于是他们说服自己这画还没有那么糟, 真的 -- 事实上,也许就该这么画.
(这样说服自己)真是危险; 为了培养一种不满足的精神而犯错会更好. 达芬奇的素描里,经常是五六次尝试才能画出一条线的准确位置. 与众不同的Porsche 911的背后,是笨拙的原型. Wright原先的Guggenheim的设计里, 右半部是个金字塔形的建筑(ziggurat),他把它倒转成现在的模样.
犯错是正常的. 不要把错误视为灾难, 而要把它们弄得容易证实和修复. 达芬奇或多或少发明了素描, 使得画画能够承受更多的负荷和探索. 开发源代码的软件错误少些,因为它承认犯错误的可能性.
如果介质能使改变变得容易, 是有帮助的. 油画颜料在十五世纪取代蛋彩的时候, 画家开始能够处理一些诸如人像画等困难的题材, 因为不象蛋彩,油画颜料可以混合和覆盖.
好的设计可以复制. 对复制的态度通常会走一条弯路. 新手还没有了解就开始模仿; 然后他有意识地试图原创; 最后,他认识到正确比原创更重要.
无知的模仿几乎就是坏设计的秘方. 如果你不知道你的想法从哪里来,你可能在模仿一个模仿者. 拉斐尔风格在十九世纪中期是如此流行,以至于每个学画的人都要模仿他, 甚至是模仿的模仿. 正是这种风气,而不是拉斐尔本人的作品,惹恼了拉斐尔前派艺术家.
有雄心的人不满足于模仿. 鉴赏力成长的第二阶段是有意识地以原创为目标.
我认为最伟大的大师们有一种忘我的精神. 他们一心想得到正确的答案,因此如果正确答案的某些部分已经被人发现了,那么没有理由不用它. 他们有足够的自信从别人那儿汲取养料,而不担心在此过程中失去自己的观念.
好的设计通常是奇特的.一些最杰出的作品有不可思议的品质: 欧拉公式, 勃鲁盖尔(Brueghel)的雪中猎人 ,SR-71, Lisp. 它们不仅是美的, 而且是奇异地美.
我不知道原因. 可能是我自己愚昧无知. 开罐器对狗来说一定也是不可思议的. 如果我足够聪明的话, 会觉得ei*pi = -1 是世界上最自然的事情. 不论如何,此公式肯定是真理.
我在本文里提到的大多数品质是可以培养的, 但我不认为奇异性可以培养. 你能做的最好的事情是有这个苗头的时候,不要去压制它. 爱因斯坦没有试图把相对论弄得奇特. 他试图找出真理, 而这真理显得很奇特.
唯一值得拥有的风格是你不能刻意追求的那种. 对奇异性来说, 尤其是这样. 没有捷径可走. 风格主义派(Mannerists), 浪漫派(Romantics)和两代美国高中生苦苦寻找的西北航路是不存在的. 到达它(奇异性)的唯一办法是经受好的(设计),然后从另一头出来.
好的设计成批出现.十五世纪佛罗伦萨的居民包括:布鲁内勒斯基 (Brunelleschi), 吉尔伯提(Ghiberti), 多纳泰罗 (Donatello), 马萨其奥(Masaccio), 菲利波·利比(Filippo Lippi), 弗拉·安吉利科(Fra Angelico), 维洛及欧(Verrocchio), 波提切利(Botticelli), 达芬奇(Leonardo da Vinci), 和米开朗基罗 (Michelangelo). 米兰当时和佛罗伦萨一样大, 你能说出多少米兰艺术家?
十五世纪的佛罗伦萨发生了一些事情,而且它是不可遗传的, 因为现在不发生了. 你必须假定无论达芬奇和米开朗基罗有什么先天的因素,米兰人也应该有. 可以米兰的达芬奇呢?
美国现在的人口大约是十五世纪佛罗伦萨的一千倍. 一千个达芬奇和一千个米开朗基罗生活在我们中间. 如果仅由DNA支配一切, 我们天天会碰到艺术杰作. 我们没有, 原因是你要创造达芬奇, 不仅需要他天生的能力, 还要1450年的佛罗伦萨.
没有什么比一群有才能的人在相关问题上进行探索更强大的了. 比较起来, 基因无足轻重: 具有达芬奇的基因不足以补偿住得离米兰近而离佛罗伦萨远. 现代人迁移得更多了, 但伟大的作品仍然不成比例地来自几个热点地区: 鲍豪斯 (Bauhaus), 曼哈顿计划, 纽约客, 洛克希德的Skunk Works, 施乐的帕洛阿尔托研究中心(Xerox Parc).
在任何时候,只有有限的课题和有限的做出伟大工作的小组. 如果你离这些中心太远, 就几乎不可能有出色的工作. 你可以在某种程度上顺应或反对这种趋势, 但你不能脱离它.(也许你能, 但米兰的达芬奇没有成功.)
好的设计通常是大胆的.历史上的每个时期,人们都会相信一些荒谬的东西, 而且是如此坚定, 你得冒着被排斥甚至暴力的风险说出不同的意见.
如果我们的时代有不同的话,真是太好了. 就我目前的观察,还没有.
这个问题不仅折磨着每个时代,而且某种程度上折磨着每个领域. 许多文艺复兴时期的作品在那个时代长期被认为是可怕的:根据Vasari的说法,Botticelli忏悔并放弃了绘画,Fra Bartolommeo和Lorenzo di Credi actually居然烧掉了部分作品. 爱因斯坦的相对论令许多同时代的物理学家感到不快, 几十年来没有被完全接受, 在法国,直到1950年代.
今天的实验性的错误是明天的理论. 如果你想发现伟大的新事物, 不该对传统智慧和理论不太涉及到的地方视而不见, 而要特别地注意它们.
作为特例,我认为看见丑陋要比想象出美丽容易. 大多数创造出美丽事物的人是通过修改他们觉得丑陋的地方来达到目标的. 伟大的作品往往是这样产生的: 某人看到某物并想, 我可以做得比这好. 乔托(Giotto)看到传统的按公式刻画出来的圣母像让几个世纪的人们感到满意,但他却觉得看上去笨拙和不自然. 哥白尼为一个同时代人普遍接受的理论深深苦恼, 觉得一定有更好的解决办法.
不能忍受丑陋还不够. 在发展出知道哪儿需要修改的嗅觉之前, 你得对该领域非常理解. 你得埋头苦干. 你成为专家之后, 你会听到内心的声音: What a hack! 一定会有更好的办法. 不要忽略这种声音,培养它们. 伟大作品的秘决是: 非常准确的鉴赏力加上能使它满足的能力.
原注
Sullivan 实际上说的是: 形式永远跟随功能. (form ever follows function.) 不过我认为这个不准确的引用更接近现代主义建筑师的意思.
Stephen G. Brush, "Why was Relativity Accepted?" Phys. Perspect. 1 (1999) 184-214.
YouTube允许日本版权所有人通过盗版创收
新浪科技讯 北京时间11月26日消息,据国外媒体报道,YouTube日前与一个由日本23家最大的电视广播商和版权机构组成的联盟签署了一项许可协议,并表示用户上传的版权内容并非是一种威胁。两年前,该联盟曾谴责YouTube放任用户上传盗版内容。
YouTube表示,部署的一项新技术能够识别用户上传内容的版权所有人,为内容合作伙伴带来收入。YouTube负责内容合作业务的副总裁大卫·埃文(David Eun)在东京举行的一次新闻发布会上阐述了YouTube的商业计划,称将重点解决创收问题。
YouTube利用视频内容创收计划的核心是Content ID,该系统首先扫描用户上传的视频内容,然后与由版权人提供的参考视频数据库进行比对。埃文说,“这一技术将继续得到改进,但它的表现已经令我们相当吃惊了。”
在发现盗版内容后,内容提供商有三种选择:封杀盗版内容;跟踪盗版内容,了解哪些用户在何时观看了盗版内容;在盗版内容中插播广告获得收入。埃文表示,目前已经有约300家合作伙伴使用了Content ID,在约90%的情况下他们会选择插播广告。
埃文称,“在被观看次数最多的视频内容中,被合作伙伴声称拥有版权的用户上传内容多于合作伙伴自己上传的内容。对于一些合作伙伴而言,内容的被观看次数因此而增长了50倍,不但会提高广告收入,还使他们能够更了解用户喜欢哪些类型的内容。”
YouTube还在试验视频内置广告。埃文表示,试验表明,按点进率计算,视频内置广告的有效性比标准显示广告高8-10倍。
过去两年中,YouTube在日本的地位得到了巩固。日本已经成为YouTube最大的海外市场。
XSLT format-number() 函数
定义和用法
format-number() 函数用于把数字转换为字符串。
语法
string format-number(number,format,[decimalformat])
参数
参数 描述
number 必需。规定要格式化的数字。
format 必需。规定格式化模式。这是用在格式化模式中的字符:
* # (表示数字。例如:####)
* 0 (表示“.”字符前面和后面的零。例如:0000.00)
* . (小数点的位置。例如:###.##)
* , (千的组分隔符。例如:###,###.##)
* % (把数字显示为百分比。例如:##%)
* ; (模式分隔符。第一个模式用于正数,第二个模式用于负数。)
decimalformat 可选。十进制格式名称。
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <body> <xsl:value-of select='format-number(500100, "#.00")' /> <br /> <xsl:value-of select='format-number(500100, "#.0")' /> <br /> <xsl:value-of select='format-number(500100, "###,###.00")' /> <br /> <xsl:value-of select='format-number(0.23456, "##%")' /> <br /> <xsl:value-of select='format-number(500100, "#######")' /> </body> </html> </xsl:template> </xsl:stylesheet> |
数学运算和XSLT
XSLT对XPath的数学性能的完全支持使人们可以做所有基本类型的算法或者更多!让我们看一下一个通过使用下面文件的值来示范这些性能的样式表:
1 2 3 4 5 |
<numbers> <x>4</x> <y>3.2</y> <z>11</z> </numbers> |
样式表的A到N每行均进行着(或者试图进行)一个不同的计算。这些计算使用上面文件中给出的数字和其他一些或者是样式表中固定的代码或者是从函数中返回的数值得到的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" omit-xml-declaration="yes"/> <xsl:template match="numbers"> A. 4 + 3.2 = <xsl:value-of select="x + y"/> B. 3.2 - 4 = <xsl:value-of select="y - x"/> C. 4 * 3.2 = <xsl:value-of select="x * y"/> D. 11/3.2 = <xsl:value-of select="z div y"/> E. 4 + 3.2 * 11 = <xsl:value-of select="x+y*z"/> F. (4 + 3.2) * 11 = <xsl:value-of select="(x+y)*z"/> G. 11 mod 4 = <xsl:value-of select="z mod x"/> H. 4 + 3.2 + 11 = <xsl:value-of select="sum(*)"/> I. floor(3.2) = <xsl:value-of select="floor(y)"/> J. ceiling(3.2) = <xsl:value-of select="ceiling(y)"/> K. round(3.2) = <xsl:value-of select="round(y)"/> L. 11 + count(*) = <xsl:value-of select="11+count(*)"/> M. 3.2 + string-length("3.2") = <xsl:value-of select="y + string-length(y)"/> N. 11 + "hello" = <xsl:value-of select="z + 'hello'"/> </xsl:template> </xsl:stylesheet> |
在我们讨论每一行具体做什么之前,让我们先看一下将样式表应用到数字文件中的结果。
A. 4 + 3.2 = 7.2
B. 3.2 - 4 = -0.8
C. 4 * 3.2 = 12.8
D. 11/3.2 = 3.4375
E. 4 + 3.2 * 11 = 39.2
F. (4 + 3.2) * 11 = 79.2
G. 11 mod 4 = 3
H. 4 + 3.2 + 11 = 18.2
I. floor(3.2) = 3
J. ceiling(3.2) = 4
K. round(3.2) = 3
L. 11 + count(*) = 14
M. 3.2 + string-length("3.2") =
6.2
N. 11 + "hello" = NaN
这个样式表对源树中的numbers元素具有一个单一的模板规则。这个模板有一系列的 xsl:value-of 指令,它们用来选择属性使用numbers元素的x、y和z子元素的数值去进行各种不同的数学计算。类似的这些数学公式可以使用XPath的全部功能来表示哪些元素或属性具有他们需要的数字;但是,这个样式表更加注重于说明与使用奇特的XPath表达式从一个文件的余部找回元素和属性相比它可用的数学运算的范围。
模板的行A将x的值(4)加到y的值(3.2)上并将他们的和7.2放到结果树中。这是非常简单的、直观的,并显示了并不需要限制在样式表数学中为整数。
行B从3.2中减掉了4得到结果为-0.8。负数并没有给XSLT处理器带来任何的困难。
警告: 对某些XSLT处理器,十进制数字的使用可能引入一个微小的误差。例如,这个例子中的"3.2 - 4"在有些处理器中得到的结果为"-.7999999999999998"。 .0000000000000002的误差很小,但从根本上说明数学并不是XSLT的强项。
行C用4乘3.2,使用星号作为乘法运算符,其结果为12.8。
行D用3.2除z元素(11),说明了一个XSLT处理器执行浮点除法运算的能力。尽管大多数的编程语言在传统上使 用斜线字符(/)表示除法运算符,但是Xpath已经将斜线字符用来分段Xpath位置路径(例如, wine/vintage 表示了vintage 元素为 wine 元素的子元素)。因此,Xpath和XSLT用字符"div" 表示除法。
行E和F显示了圆括号与在正常的数学符号中具有同样的操作优先权:不使用圆括号,先乘后加,所以4 + 3.2 * 11 = 4 + 35.2。对"4+3.2"使用圆括号后,先进行加法运算,所以(4 + 3.2) * 11 = 7.2 * 11。
行G示范了mod 运算符,它得到了两数相除的余数。例中为11 mod 4 结果为3,因为11除以4得2余3。这个运算符主要用来检查一个数是否能被另一个数均分;即检查大数mod小数是否等于0。
行H示范了sum() 函数。用节点列表作为参数,它加和了列表中所有节点的数值。在本例中星号的意思是"范围节点内的所有子节点"--即numbers元素的x, y和z 子元素。
行I和J示范了floor() 和ceiling() 函数。如果它们传入的参数为整数,它们即返回该整数。如果传入floor() 一个非整数,将返回一个小于该数的最大整数。本例中为floor(3.2)结果为3。ceiling函数将返回大于该数(非整数)的最小整数;例中 ceiling(3.2)结果为4。
行K的round()函数把一个非整数舍入为一个最接近的整数。 当传入参数为3.2时,返回值为3;传入3.5或3.6时,它的返回值将变为4。
行L具体表现了另一个Xpath函数:count(),它将返回作为参数传给它的节点集的个数。Xpath提供几个函数,当数学上不明确时,返回数值并可以用于各种计算:count(), last(), position()和string-length()。行M示范了string-length(),它将返回该字符串的长度。
行N显示了当试图对一些不是数字的东西执行数学运算时得到的结果:当11加上字符串"hello"时,得到的结果为字符串"NaN",即"Not a Number."的缩写。当你把一个数字作为一个元素的内容或者是属性值,然后用它来进行计算,将不能保证它真正的是一个数字,所以XSLT明确定义了不能实行的情况的状态,使之更加容易的检测和处理你的代码。
XSLT是用来处理文本,而不是数字;但是你可以用作为XSLT一部分提供的数学运算符来构建和执行更多复杂的计算。例如,下面的样式表,它可以接受任何文件作为输入,计算 pi的值。其结果的精度依赖于迭代变量的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="text"/> <!-- Compute pi. Based on Leibniz's algorithm that pi/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11... which I did as pi = 4 - 4/3 + 4/5 - 4/7 + 4/9 - 4/11... --> <xsl:variable name="iterations" select="80000"/> <xsl:template name="pi"> <!-- named template called by main template below --> <xsl:param name="i">1</xsl:param> <xsl:param name="piValue">0</xsl:param> <xsl:choose> <!-- If there are more iterations to do, add the passed value of pi to another round of calculations. --> <xsl:when test="$i <= $iterations"> <xsl:call-template name="pi"> <xsl:with-param name="i" select="$i + 4"/> <xsl:with-param name="piValue" select="$piValue + (4 div $i) - (4 div ($i + 2))"/> </xsl:call-template> </xsl:when> <!-- If no more iterations to do, add computed value to result tree. --> <xsl:otherwise> <xsl:value-of select="$piValue"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="/"> <xsl:call-template name="pi"/> </xsl:template> </xsl:stylesheet> |
循环通过利用一个递归的命名模板(named template)来实现。根据迭代设置显示,该样式表得到的结果为:
3.1415676535897985
经过多次迭代,结果仅仅精确到小数点后的第四位数字。当然如果你想认真地计算PI的值,有更多合适的编程语言。但是知道了在必要的时候可以使用XSLT来做一些相对复杂的数学运算还是很不错的。
补充一个sum函数的用法:
1 |
<xsl:value-of select="sum(/Price[normalize-space(.) !=''])" /> |
Schema中无顺序的Element的写法
很郁闷的,在网上搜不到相关的内容。
很庆幸,Felix Validate给出很直观的错误提示。
试验了好久,终于写对了,记录一下。
1 2 3 4 5 6 |
<xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element name="subtitle" type="xs:string" minOccurs="0" maxOccurs="unbounded" /> <xs:element name="question" type="question_t" minOccurs="1" maxOccurs="unbounded" /> </xs:choice> |
这么写相当于
1 |
(subtitle*|question+)+ |