Mako 模板系统.doc_第1页
Mako 模板系统.doc_第2页
Mako 模板系统.doc_第3页
Mako 模板系统.doc_第4页
Mako 模板系统.doc_第5页
已阅读5页,还剩56页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Mako 模板系统文档一、 使用基础这一节介绍 Mako template 的Python API. 如果你在 Pylons 之类的 web 框架中使用 Mako,那么集成 Mako API 的工作也许已经给你做好了。你可以直接跳到下一节,语法。最简单的办法是通过 Template 类,创建模板并渲染之:from mako.template import Templatemytemplate = Template(hello world!)print mytemplate.render()上述例子中,传递给 Template 的文本参数被编译成了一个 python 的模块。该模块有一个 render_body() 函数,用于输出模板内容。当 mytemplate.render() 被调用时,Mako 会为此模板创建起一个运行时环境,并调用 render_body() 函数,然后捕获其输出到缓冲区,然后返回其字符串内容。render_body() 函数中的代码可以访问包含了一些变量的一个名称空间。你可以传递额外的关键字参数给 render() 方法,这些参数将转化为可被访问的变量:from mako.template import Templatemytemplate = Template(hello, $name!)print mytemplate.render(name=jack)template.render() 方法会让 Mako 创建一个 Context 对象,其中包含了所有该模板可访问的变量的名称,以及一个用于捕获输出的缓冲区。你也可以自己创建 Context 对象,并命令模板利用此 Context 来 render,用 render_context 方法即可:from mako.template import Templatefrom mako.runtime import Contextfrom StringIO import StringIOmytemplate = Template(hello, $name!)buf = StringIO()ctx = Context(buf, name=jack)mytemplate.render_context(ctx)print buf.getvalue()1 使用基于文件的模板你也可以从文件中加载 Template 的内容,使用 filename 关键字参数:from mako.template import Templatemytemplate = Template(filename=/docs/mytmpl.txt)print mytemplate.render()为提高性能,从文件中加载的 Template, 可以将它产生的模块的源代码以普通 python 模块文件的形式(.py),缓存到文件系统中。只要加一个参数 module_directory 即可做到这一点:from mako.template import Templatemytemplate = Template(filename=/docs/mytmpl.txt, module_directory=/tmp/mako_modules)print mytemplate.render()当上述代码被 render 的时候,会创建文件/tmp/mako_modules/docs/mytmpl.txt.py. 下一次 Template 对象被用同样参数调用的时候,就会直接重用该模块文件。2 使用 TemplateLookup在模板中,我们有时候需要调用或引用其他模板的内容,这就牵涉一个模板查找定位的问题,通常用简单的 URI 字符串来定位。我们用TemplateLookup类来负责这个任务。该类的构造函数需要传递一系列可供查找模板的路径的列表。然后我们再将此 TemplateLookup 对象用关键字参数的形式传递给 Template 对象。from mako.template import Templatefrom mako.lookup import TemplateLookupmylookup = TemplateLookup(directories=/docs)mytemplate = Template( hello world!, lookup=mylookup)上述例子中创建了一个文本模板,其中有一个对 header.txt 文件的包含引用。而从何处去查找 header.txt, 则由 TemplateLookup 指明,是 /docs 目录。通常,应用程序会把模板用文本文件的形式保存在文件系统中。而为了方便起见,我们可以直接通过 TemplateLookup 来获取模板对象,利用 TemplateLookup 的 get_template 方法,并传递模板的 URI 作为参数:from mako.template import Templatefrom mako.lookup import TemplateLookupmylookup = TemplateLookup(directories=/docs, module_directory=/tmp/mako_modules)def serve_template(templatename, *kwargs): mytemplate = mylookup.get_template(templatename) print mytemplate.render(*kwargs)lookup 在查找模板时通过向其中的每一个搜索路径附加我们提供的模板 URI 的方式,来尝试获取模板文件。如果找不到则引发 TopLevelNotFound 异常,这是一个 Mako 的自定义异常类型。当 lookup 找到模板时,它还会给 Template 指定一个 uri 属性,这个 uri 就是传递给 get_template() 方法的参数。Template 可以用此 uri 来计算出其对应的模块文件的名称。比如在上述例子中,/etc/beans/info.txt 这个 URI 名称参数,会导致创建模块文件 /tmp/mako_modules/etc/beans/info.txt.py.3 设定集合的大小TemplateLookup 同时也会在内存中缓存一组模板,所以并不是每一次请求都会导致模板的重新编译和模块重新加载。默认 TemplateLookup 的大小没有限制,但你可以通过 collection_size 参数来限制它:mylookup = TemplateLookup(directories=/docs, module_directory=/tmp/mako_modules, collection_size=500)以上的 lookup 会持续加载模板到内存中,直到达到 500 的时候,它就会清除掉一定比例的模板缓存项,根据“最近最少访问”原则。4 设置文件系统检查另一个 TemplateLookup 相关的标志是filesystem_checks. 默认为 True, 每一次 get_template() 方法返回模板后,原始的模板文件的 revision time 会和上次加载模板的时间做对比,如果文件更新,则会加载其内容,并重新编译该模板。在生产环境下,设置 filesystem_checks 为 False 可以带来一定的性能提升(和具体的文件系统有关)。5 使用 Unicode 和 EncodingTemplate和TemplateLookup都可以接受output_encoding和encoding_errors参数,用来对输出以 Python 支持的任何方式进行编码:from mako.template import Templatefrom mako.lookup import TemplateLookupmylookup = TemplateLookup(directories=/docs, output_encoding=utf-8, encoding_errors=replace)mytemplate = mylookup.get_template(foo.txt)print mytemplate.render()另外,render_unicode() 方法可以将模板的输出转换为一个 Python 的 Unicode 对象返回:print mytemplate.render_unicode()上面的方法调用未提供输出编码参数,你可以通过下列语法来进行编码:print mytemplate.render_unicode().encode(utf-8, replace)注意, Mako 能将数据返回为任何 encoding 或 unicode 的能力暗示着,模板内部的输出流是一个 Python unicode 对象。这种行为的详细描述在The Unicode Chapter.6 处理异常模板异常可能在两种截然不同的地方出现。第一种是当你查找,分析和编译模板时,另一种是当你运行模板的时候。在模板的运行过程中,异常通常从产生问题的 python 代码出抛出。Mako 有其独立的一套异常类,它们大多数针对模板构造过程的查找和词法分析/编译阶段。Mako 还提供了一些库函数,这些函数用来帮助提供 Mako 相关的异常栈跟踪信息,并可用纯文本或 HTML 方式格式化异常信息。不管是哪种情况,这些处理函数的作用在于将 Python 文件名,行号,以及代码例子转换为 Mako 的模板文件名,行号,以及代码范例。在跟踪栈里对应于某个 Moko 模板的每一行,都回被转换为和源模板文件相关的。为了格式化异常跟踪信息,系统提供了 text_error_template 和 html_error_template 函数。它们都利用了 sys.exc_info() 函数来获取最近抛出的异常信息。下面是常见的用法:from mako import exceptionstry: template = lookup.get_template(uri) print template.render()except: print exceptions.text_error_template().render()如果使用 HTML 的输出函数:from mako import exceptionstry: template = lookup.get_template(uri) print template.render()except: print exceptions.html_error_template().render()HTML 输出函数也内建到了 Template 中。通过 format_exceptions 这个标志位参数。这样,任何在 template 的 render 阶段引发的异常,都会使得 template 的输出内容被 html_error_template 方法的输出所替代。template = Template(filename=/foo/bar, format_exceptions=True)print template.render()注意,上述模板的编译阶段发生在你构造 Template 对象本身的时候,并且没有定义输出流。所以,在查找/解析/编译阶段引发的异常不会被处理,而是像平常那样被继续抛出到更高层次的调用堆栈上(繁殖, propagate)。虽然 pre-render traceback 不会包含任何 Mako 特定的行,这意味着发生在 rendering 之前的异常,以及 rendering 过程中发生的异常,需要用不同的办法分别处理。因此,上面的 try/except 模式可能是比较通用的一种写法。被错误模板函数使用的内部对象是 RichTraceback. 该对象也可以被直接用于提供自定义错误视图。下面是一个范例应用,可以描述其一般使用的 API:from mako.exceptions import RichTracebacktry: template = lookup.get_template(uri) print template.render()except: traceback = RichTraceback() for (filename, lineno, function, line) in traceback.traceback: print File %s, line %s, in %s % (filename, lineno, function) print line, n print %s: %s % (str(traceback.error._class_._name_), traceback.error)关于RichTraceback的更深入信息可以查阅 mako.exceptions 的模块级文档。二、 语法Mako 模板是从文本流中进行解析的,流中可以包含任意内容: XML, HTML, email 文本,等等。模板中可以包含 Mako 特定的指令(directives),可用于表示变量或表达式替换,控制结构(如条件和循环),服务器端注释,整段的 Python 代码,以及各种用于提供附加功能的标签(tags)。所有这些将被编译为真实的 Python 代码。这意味着你可以在 Mako 模板中利用 Python 几乎所有的强大特性。1 表达式替换最简单的表达式是变量替换。其语法是 $,受 Perl, Genshi, JSP EL 和其他一些语言的启发:this is x: $x以上代码中,x 的字符串表示形式将被应用到模板的输出流中。x 的值通常来源于你提供给模板 rendering 函数作为参数的 Context 变量。如果 x 的值未指定给模板,并且也未指定为局部变量,则会估算为一个特殊的值 UNDEFINED.$ 中的内容会被 Python 直接估算,所以各种表达式都是支持的:pythagorean theorem: $pow(x,2) + pow(y,2)在 render 到输出流之前,表达式的结果总是被估算为一个字符串。2 表达式转义(escaping)Mako 包含了一系列内建的转义机制,包括 HTML, URI 和 XML 转义,以及 trim 函数。转义的动作可以通过 | 运算符附加到表达式后面:$this is some text | u上例中对表达式进行了 URL 转义,其结果是:this+is+some+text. 其中 u 代表 URL 转义,与之类似的,h 代表 HTML 转义,x 代表 XML 转义,而 trim 则是通常的 trim 函数。可以在Filtering and Buffering中获取更多关于过滤器函数的内容,包括如何创建你自己的过滤器。3 控制结构控制结构指的是控制程序流程的那些语法 条件(如 if/else),循环(如 while 和 for),以及 try/except 之类。在 Mako 中,控制结构用 % 后附加常规 Python 控制结构的写法,并用另一个 % 语法 end 结束语句块。其中 是该表达式的关键字:% if x=5: this is some output% endif% 可以出现在一行里的任何位置,只要其前面没有其他文本;缩进是无所谓的。Python 中的所有“冒号”表达式在这里都完全支持,包括 if/elif/else, while, for 甚至 def,尽管 Mako 有其内建的功能更强大的 def 标签。% for a in one, two, three, four, five: % if a0 = t: its two or three % elif a0 = f: four/five % else: one %endif% endfor4 注释注释有两种形式。单行注释在一行中以 # 开头(前面可以有空白):# 这是一个注释.text .而多行注释则使用 . 文本. 的语法: 这里是注释 更多注释注意,这是 Mako 0.1.3 的新特性。在此之前的版本中,注释的语法是单个 # 符号,而这和 CSS 的元素指示语法冲突,并且不能很好的处理多行注释。5 换行过滤器(Newline Filters)反斜线 () 字符放在任意一行的后面,会吃掉一个换行符。here is a line that goes onto another line.上述语法会产生下列文本:here is a line that goes onto another line.6 Python 语句块任意 python 语句块都可以用 标签来定义:this is a template% for elem in y: element: $y% endfor在 内定义的 python 代码,其整体的缩进量是不重要的,但是他们内部的语句之间必须有正确的缩进层次(因为这里没法使用 end),Mako 的编译器会调整 python 语句块的缩进层次与其周围的其他生成的 Python 代码相配合。7 模块级的语句块 的一个变体是 ,代表模块级别的代码块。其中的代码会在模板的模块级别执行,而不是在模板的 rendering 函数中。所以,这段代码不能访问模板的 context,仅在模板被加载到内存时被执行(有可能是相对于每应用程序仅执行一次,或者多次,这取决于运行时环境)。可以使用 来定义模板的导入语句:在模板中,可以在任何位置,定义任意数目的 语句块;他们在编译产生的模块文件中出现的次序和定义时相同。8 标签Mako 还提供了标签。所有标签的语法都一样,类似于 XML 标签,不同之处在于其标签名称必须以 % 开头。标签的关闭可以用反斜杠的内联形式,或者独立的关闭标签: this is a def每种标签都定义了一系列特定的属性。有些属性是必须的。并且,很多属性支持估算操作(evaluation),也就是说你可以在属性文本中嵌入一个表达式(用 $ 语法)。属性是否支持运行时的估算,取决于标签的类型,以及该标签是如何编译成模板的。想知道某个标签的属性是否支持估算,最好的办法就是去试验它!如果不合法,词法器会告诉你。下面是所有标签的一个简单介绍:1 定义了当前模板的总体特性,包括缓存参数,以及模板被调用时期待的参数列表(非必须)。定义缓存特性:关于 使用的细节在The body() method和Caching中有深入描述。目前只有 标签是模板唯一的,其他的会被胡略,这在将来的发布版本中也许会被改变,但现在请确认这一点。2 类似于其他模板语言的一个标签,%include 接受一个文件名称作为参数,调用被引用文件的输出结果。 hello world3 %def 标签用于定义包含一系列内容的一个 Python 函数,此函数在当前模板的其他某个地方被调用到: this is myfunc, x is $x$myfunc(7)%def 标签比 Python 的 def 要强大一些,因为 Mako 的编译器为 %def 提供了很多额外服务,比如可以导出 defs 为模板“方法”,自动传播当前的 context (原文:automatic propigation of the current Context),缓冲/过滤/缓存 标志位,以及带有内容的 def 调用,这使得 defs 的包可以被以参数的形式,提供给其他的 def 调用(不像听起来那么困难)。可以在Defs中了解 %def 的详细内容。back to section top4 %namespace 是 Mako 中相对 Python里 import 语句的等价物。它允许访问其他模板文件的所有 rendering 函数和元数据,纯文本的 python 模块,以及局部定义的函数“包”。%namespace 编译后产生的对象是 mako.runtime.Namespace 的一个实例,这是在模块中被用来引用模板特定的信息(如当前的 URI,继承结构以及其他一些东西)的一个中心结构,名称空间的详细描述在Namespaces中。5 允许模板可以在继承链中安排其自身的位置。这是其他很多模板语言都有的一个熟悉的概念。当使用 %inherit 标签时,首先,控制权被转交给继承树最顶层的父模板,由它来决定如何配合继承自它的子模板来处理其中的调用区域(calling areas)的内容。Mako 在这方面提供了很多灵活性,包括动态继承(dynamic inheritance), 内容包装(content wrapping), 以及多态的方法调用(polymorphic method calls). 详见Inheritance。6 call 标签用于调用 标签,可传递额外的内嵌内容。详细描述在Calling a def with embedded content and/or other defs.7 处理多行注释: these are comments more comments# 用于处理单行注释。8 该标签使得 Mako 的词法器对模板指令的常规解析动作停止,并以纯文本的形式返回其整个内容部分。该语法可以用来书写 Mako 的文档: heres some fake mako $syntax $x三、 定义函数1 Defsdef 是一个简单的标签,用于给任意文本块或代码块定界。它在模板最终生成的 Python 代码里是一个可调用的函数。 hello world通常我们可以通过表达式来调用它们:the def: $hello()如果 没有嵌套定义在另一个 中,则称为顶层的 def, 它可以在模板的任何地方被使用,甚至可以在定义它的位置之前。所有的 defs, 不管是不是顶层的,都可以访问当前的上下文名称空间,和模板的访问权限完全一样。设想下列模板在执行时被指定了一个包含 username 和 accountdata 变量的上下文:Hello there $username, how are ya. Lets see what your account says:$account() Account for $username: % for row in accountdata: Value: $row % endforusername和accountdata两个变量将会显示在主模板的 body 中,同样也会显示在account()def 的 body 中。既然 defs 不过就是 python 函数,你自然也能够定义和传递参数了:$account(accountname=john) account name: $accountname, type $type当你为 def 定义参数时,他们需要遵从 Python 的规定(比如,除了提供了默认值的关键字参数之外的所有参数,都需要提供)。这和上下文层次的变量不同,后者对不存在的名称会估算为 UNDEFINED 而不是出错。2 从其他文件调用 defs顶层的 被编译到模板对应的模块中,并且可以被从外部调用;包括从其他模板,或是普通的 Python 代码来调用。从其他模板中调用 有点像使用 差别在于,你是在调用模板中的一个函数,而不是整个模板。远程的 调用也有点类似于 Python 中调用另一个模块中的函数的情形。需要有一个“导入”的步骤,以便从其他模板中萃取出名称,添加到你自己的模板中;然后这些名称的函数才可以被调用。要导入另一个模板,使用 标签:上面的标签添加了一个局部变量 mystuff 到当前范围中。然后,只要调用 mystuff 中的函数即可:$mystuff.somedef(x=5,y=7) 标签还支持类似 Python import 语句的一些其他的语义,包括将名称提取到局部变量空间中,或使用 * 来代表所有名称,使用 import 属性:这里只是对名称空间的概念做了一个简单的介绍,名称空间是 Mako 的一个核心概念,在文档中有独立的章节介绍。更多的细节和例子,见Namespaces。3 Defs中的 Defsdef 模型遵循 Python 中关于闭包的一些规则。在一个 中定义另一个 ,会将它定义在父 def 的外围环境(enclosing scope) 中: a sub def im the def, and the subcomopnent is $subdef()就象 Python 中一样,定义在内嵌 之外的名称,在其内部一样存在: inner, x is $x, y is $y outer, x is $x, y is $y在 def 内的赋值语句会创建一个 def 范围内的局部变量(再一次的和 Python 自身语法吻合)。比如下面的代码就会引发错误: # error ! somedef, x is $x .因为对 x 的赋值将 x 定义为了 somedef 范围内的局部变量,而试图输出“外部”版本的 x 是访问不到的。4 调用方自带内容或内嵌函数的方式调用 defdef 的另一个方面是它可以带内容的进行调用。也就是,当你调用 def 时,同时定义一个块的内容(或多个块),这些块将提供给你要调用的 def. 这种调用方式的主要目的是为了创建自定义的,可嵌套的标签,就象其他模板语言的自定义标签生成系统 外部的标签控制内嵌标签的执行,并且可以和它们沟通状态信息。只有在 Mako 中,你才不需要使用任何外部的 Python 模块,你可以直接在你的模板中定义可任意内嵌的标签。为了达到这个目标,需要通过 标签而不是常规的 $ 语法来调用目标 def. 这样,目标 def 就会在其上下文中获得一个 caller 变量,其中包含一个名称空间,在此名称空间中包含了调用者的内容部分(body), 以及 标签中定义的其他 defs. 而调用者的内容(body) 可通过 body() 方法来取得: $caller.body() I am the table body.这会产生下列输出 (空白已格式化): I am the table body. body() 可以被执行多次,或根本不执行。这意味着你可以使用带内容的 def 调用(def-call-with-content)来创建迭代器(iterators),条件语句等: % for x in range(1,count): $caller.body() % endfor hi输出:hihihi一个自定义的“条件”标签: % if expr: $caller.body() % endif im the result输出:im the result但还有更精彩的。body() 函数还可以传递参数: % for item in somedata: % for col in item: $caller.body(col=col) % endfor % endfor Body data: $col输出(空白以格式化):译注:似乎有误!应该是3行3列表格 Body data: 1Body data: 2Body data: 3 Body data: 4Body data: 5Body data: 6 Body data: 7Body data: 8Body data: 9 你不用仅盯着调用 body() 函数,在调用方可以定义任意多个 callables,使得 标签可定制所有布局: # a layout def $caller.header() $caller.sidebar() $caller.body() # calls the layout def I am the header sidebar 1 sidebar 2 this is the body上述代码会输出(空白已格式化): I am the header sidebar 1 sidebar 2 this is the body 利用 你可以做很多事情。可以创建表单控件库(form widget libraries),比如一个自包含的 标签,以及一组内嵌的 HTML input 元素,或者用 或其他元素创建可移植的包装控件,你可以创建标签来解释数据行,比如从数据库中得到的数据,然后将行的每一列传递给 body() 的一个可调用函数,这样就可以对数据行进行任何你想要的排版。基本上,你在其他系统中通过“自定义标签”或标签库想做的事情,Mako 中都可以通过 或通过用 调用Python 函数的方式来实现。四、 运行时环境本节会介绍一点模板中可访问的对象和内建函数的内容。1 ContextContext 是模板被第一次执行前创建的一个核心对象,它负责和模板外部做所有的交互。它由两个主要的组件组成,1. 输出缓冲区,这是一个类似文件的对象,比如 Python 的 StringIO;2. 变量字典,其中的所有变量均可在模板中自由引用,该字典是由传递给 template.rener() 方法的参数,以及一些由 Mako 运行时环境提供的内建变量组成。2 缓冲区缓冲区存储在 Context 中,通过 context.write() 方法可以写缓冲区。通常你不需要关注此方法,因为模板中的文本和 $ 形式的表达式,都会自动将输出提交到该方法。只有在下列几个应用场景下你才可能需要用到它:1. 处理各种过滤/缓冲(详见Filtering and Buffering),2. 用编程的方式将内容发送到输出流,比如在一个 块中。实际的缓冲区可能不是原来发送给 Context 对象的那个,因为在各种过滤/缓存的场景下,可能会 push 一个新的缓冲区到 context 内部的缓冲区栈上。正因为此,只要我们记住始终调用 context.write() 方法,就可以确保内容被发送到顶层的缓冲区。3 上下文变量当模板被编译为 python 模块时,其页面内容被包含在 render_body 这个函数中。其他顶层的 defs, 会在其各自独立的函数中定义,函数名被附加了一个前缀 render_(比如 render_mydef)。在这些函数中,所有在本地没有定义的变量(比如通过赋值或模块导入的方式定义的),都会从 Context 对象的变量字典中提取。 如果引用当前上下文中不存在的变量会怎么样?- 你取得的值将是一个特殊的值 UNDEFINED. 它是 mako.runtime.Undefined 类的一个全局变量。UNDEFINED对象会在你尝试调用 str() 时抛出错误。这会在尝试在表达式中使用它的时候发生。 为什么不直接返回 None 呢?UNDEFINED 更明确,可以和人为传递到 Context 中的 None 加以区分,以及和没有提供值的变量区分开来。 为什么对它调用 str() 时会引发异常,而不是返回空字符串呢?- Mako 一直在努力遵循 python 的哲学 “明确胜于隐晦”(explicit is better than implicit). 具体来说,模板作者应该处理值丢失的情况,而不是默默的任由其出错。因为 UNDEFINED 和 python 的 True 或 False 一样,是个单件(Singleton) 对象,你可以用 is 运算符来检查它: % if someval is UNDEFINED: someval is: no value % else: someval is: $someval % endif另一个值得注意的方面是,Context 的变量字典是不可变的。当然,因为是纯 python 的方式,你可以修改 context 的变量字典中的变量,但这恐怕不会如你想像。原因是,Mako 会在很多情况下会创建 Context 对象的副本,并将这些副本传递给模板中的各种元素,以及执行过程中可能用到的子模板。所以,修改本地 Context 中的值,不一定会在模板的其他部分生效。Mako 创建 Context 副本的一个例子是,在模板体中进行对顶层 def 的调用(context 被用于传递局部变量到 def 的范围中;因为在模板体内,他们以内联函数的形式出现,Mako 会尝试让他们用这种方式工作)。另一个例子是在继承链中(在链中的每个模板都有其不同的 parent 和 next,而这两个变量就保存在各自唯一的 Context 对象中)。 那么,我们如何设定相对于一个模板请求过程的全局变量呢?- 只要在模板初次运行时给 Context 提供一个字典即可,然后所有的地方就都可以向该字典中 get/set 变量了。比如叫做 attributes:运行模板:output = template.render(attributes=)在模板中,直接引用该字典:foo attribute is: $attributesfoo 为什么attributes 不是 Context 的内建特性呢?- 这也是 Mako 替你的应用程序尽量少做决定的一个体现。也许你不想在模板里用这种技术读写和共享数据,又或者你想用不同的变量名或数据结构来传递。再一次的,Mako 宁愿用户明确一点。4 上下文方法和访问器(Context Methods and Accessors)Context 的主要成员包括: contextkey/context.get(key, default=None)- 类似字典方式的访问器。通常你在模板中使用的变量,如果在局部没有定义,则会去上下文中获取。当你要使用一个在别处已经定义的(比如传递给 %def 调用的局部参数)变量时,可以用字典访问语法或 get 方法。如果没有提供 key, 则和字典类似,会引发 K

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论