CN105095348A - 一种通过xml动态配置网站的方法 - Google Patents
一种通过xml动态配置网站的方法 Download PDFInfo
- Publication number
- CN105095348A CN105095348A CN201510312172.7A CN201510312172A CN105095348A CN 105095348 A CN105095348 A CN 105095348A CN 201510312172 A CN201510312172 A CN 201510312172A CN 105095348 A CN105095348 A CN 105095348A
- Authority
- CN
- China
- Prior art keywords
- plug
- unit
- layout
- xml
- attribute
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Granted
Links
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F16/00—Information retrieval; Database structures therefor; File system structures therefor
- G06F16/90—Details of database functions independent of the retrieved data types
- G06F16/95—Retrieval from the web
- G06F16/958—Organisation or management of web site content, e.g. publishing, maintaining pages or automatic linking
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F16/00—Information retrieval; Database structures therefor; File system structures therefor
- G06F16/20—Information retrieval; Database structures therefor; File system structures therefor of structured data, e.g. relational data
- G06F16/21—Design, administration or maintenance of databases
Landscapes
- Engineering & Computer Science (AREA)
- Databases & Information Systems (AREA)
- Theoretical Computer Science (AREA)
- Data Mining & Analysis (AREA)
- Physics & Mathematics (AREA)
- General Engineering & Computer Science (AREA)
- General Physics & Mathematics (AREA)
- Information Retrieval, Db Structures And Fs Structures Therefor (AREA)
Abstract
一种通过XML动态配置网站的方法。用户可以在XML文件中通过扩展标签1<extension>来定义部件,扩展标签1包含一个扩展目标2属性用于指明在页面中加载该类部件的方法类,以及一个扩展点3属性用于指明解析该部件XML内容的解析器,用户可以在扩展标签1中对部件进行配置(如设置插件的显示内容)或组装(如在布局中***插件),***启动时会通过扩展点3获取解析该部件的解析器并将该部件的XML内容映射成一个java对象4,页面调用时会通过扩展目标2计算该java对象4(根据运行环境判断是否显示该部件以及根据部件属性生成前台样式)生成网页组件5,从而使得没有编程经验的人仅通过xml就能深入地定制网站。
Description
所属技术领域
本发明涉及一种通过XML动态配置网站的方法。
背景技术
XMAP是一个能把XML映射到Java对象的类库,通过对XML中的各标签进行遍历解析,将解析的值放入声明好的java对象中,这样一来可以通过XML配置java对象,达到模块化的效果,但解析的过程很麻烦,需要复杂的代码来实现对每个java对象的映射,不适于新手来操作。
发明内容
为了克服现有的XMAP类库不易于操作的不足,本发明提供了一套完整的解析器,涵盖了一个网站所必需的各个组成部件(如布局、插件),用户可以通过扩展的方式迅速定位到一个部件的解析器并方便地配置该部件。
本发明解决其技术问题所采用的技术方案是:在XML文件中通过扩展标签<extension>来定义部件,扩展标签包含一个扩展目标属性用于指明在页面中加载该类部件的方法类,以及一个扩展点属性用于指明解析该部件XML内容的解析器,用户可以在扩展标签中对部件进行配置(如设置插件的显示内容)或组装(如在布局中***插件),***启动时会通过扩展点获取解析该部件的解析器并将该部件的XML内容映射成一个java对象,页面调用时会通过扩展目标计算该java对象(根据运行环境判断是否显示该部件以及根据部件属性生成前台样式)生成网页组件,从而使得用户可以通过XML方便地配置网站。
本发明的有益效果是,可以让没有编程经验的人仅通过xml就能深入地定制产品,包括数据架构和文档类型,表单,生命周期,***,网页用户界面(按钮、选项卡、链接、视图、主题),工作流。
附图说明
图1是本发明的XML配置数据架构、文档类型示意图
图2是本发明的XML配置目录示意图
图3是本发明的XML载入目录示意图
图4是本发明的XML注册插件类型示意图
图5是本发明的XML实例化插件示意图
图6是本发明的暴露插件变量示意图
图7是本发明的插件调用前台模板示意图
图8是本发明的目录生成词汇树示意图
图9是本发明的下拉列表显示词汇树示意图
图10是本发明的提取XML中的扩展框架示意图
图11是本发明的根据依赖条件挂起、加载扩展框架示意图
图12是本发明的通过XML配置信息将扩展框架填充完整示意图
图13是本发明的通过XML配置信息操作插件示意图
图14是本发明的注册布局示意图
图15是本发明的提取布局示意图
图16是本发明的实现布局示意图
图17是本发明的通过属性配置布局行示意图
图18是本发明的通过变量映射控制插件模式示意图
图19是本发明的通过功能映射控制插件模式示意图
图20是本发明的通过插件模式重用布局示意图
图21是本发明的通过标记功能测试方法示意图
图22是本发明的通过插件模式重用插件示意图
图23是本发明的XML定制网站综述示意图
具体实施方式
如图1所示,***启动时会将图1左侧的xml标签语言翻译成图1右侧的数据架构和文档类型,图1中部的代码会对读取的扩展(extension)进行判断:
当扩展点(point)为文档类型(doctype)1-1且其标签为文档类型(doctype)1-2时,会用文档类型描述符(DocumentTypeDescriptor)1-3实例化一个文档类型,该例实现的文档类型名叫文件夹(Folder),该文档类型还包括了普通(common)数据架构、都柏林(dublincore)数据架构,文件夹化(Folderish)面元;
当扩展点(point)为文档类型(doctype)1-1且其标签为面元(facet)1-4时,会用面元描述符(FacetDescriptor)1-5实例化该名叫文件夹化(Folderish)的面元;
当扩展点(point)为架构(schema)1-6时会根据其标签名架构(schema)用架构描述符(SchemaBindDescriptor)1-8实例化该数据架构,该架构的名为dublincore,前缀(prefix)为dc,其引用地址(src)为shcema文件夹下的dublicore.xsd文件1-9,在该例中列出了部分都柏林(dublincore)数据架构属性,包括字符串格式的标题(title)、描述(description)及字符串列表格式的主题(subjects)。
如图2所示,***启动时会根据图2左侧的xml标签语言生成一张连接到postgresql数据库的目录:
***先用SQL目录描述符(SQLDirectoryDescriptor)将110nsubjects目录2-1实例化为配置信息(config)2-2,再将缓存最大容量(cacheMaxSize)2-3和缓存超时时长(cacheTimeout)2-4存入缓存。根据数据源标签(<dataSource>)2-5找到其对应的服务器配置并用获取连接方法(getConnection)2-6获取一个到Postgresql的连接,可以看到生成的连接包括了数据库位置jdbc:postgresql://localhost:5432/postg,用户名postgr。在架构管理(schemaManager)中提取架构名(schemaName)2-7为110nxvocabulary的架构,架构(schema)2-8展示了110nxvocabulary对应的属性,包括string类型的id、parent,该架构被实例化后的样子如2-9所示。提取该架构的各个字段名(fieldName)2-10并将其塞入架构字段表(schemaFieldMap)2-11,当字段名2-12(同2-10)与XML中idField标签2-13中的内容“id”2-14相同时,设定该字段为架构的关键字段并规定其不许为空如2-15所示。该字段的数据类型2-16会被设置为该栏的类型(ColumnType)2-17,如果XML中的Id自动增加标签(autoincrementIdField)2-18中的值为true,会通过条件判断2-19并将该栏的类型设置为AUTOINC。如果该栏在架构中包含默认值2-20,会将该默认值(defaultValue)2-21设置到该栏。最后将通过连接(sqlConnection)2-22(同2-6),刚组建的表(table)2-23,数据文件名(dataFileName)2-24,建表策略(createTablePolicy)2-25来在postgresql数据库中建立名为110nsubjects的表。
如图3所示,***会根据xml中的建表策略、架构及数据源在postgresql数据库中建立该目录并导入数据:
当建表策略为从不(never)3-1时直接跳过设置,当建表策略为缺失栏目时建表(on_missing_column)3-2时,会用hasMatchingColumns方法3-3检验是否含有缺失行,该方法会调用getMissingColumns方法3-4来寻找缺失行,该方法会先查找数据库中已存在的同名表(110nsubjects)并获取其各栏目名如3-5所示,再获取新载入的110nsubjects表3-6,将原始栏目3-5中不存在的新栏目3-7载入缺失栏目(missingColumns)3-8。如果缺失栏的尺寸大于0意味着存在缺失栏,将用addMissingColumns方法3-9为110nsubjects表添加新栏目label_new,再用createTable方法3-10重新建表,该方法将创建一个授权声明(stmt)3-11,该声明包括了到postgresql数据库的连接信息2-6,用该声明先执行删除旧表语句(dropSql)3-12,再根据新架构执行建表语句(createSql)3-13,最后再执行设置id栏为主键这样的后置建表语句(sql)3-14。建完表后用loadData方法3-15为该表载入数据,XML通过数据文件标签(<dataFile>)3-16声名了directories/110nsubjects.csv为该表载入信息的地址,***将把该地址(dataFileName)3-17中的内容导入输入信息流(InputStream)及csv解读器(csvReader)中,通过csv解读器提取110nsubjects.csv中的各栏目名(columnNames)3-18,并据此生成一条SQL***语句(insertSql)3-19,将110nsubjects.csv中每行的内容3-20读取到栏目值(columnValues)3-21,并根据判断条件把该值转化成架构中对应的数据类型3-22,将这些值***3-19组成带参数的SQL***语句3-23,执行该语句后将在postgresql数据库中***该行的内容如3-24所示。
如图4所示,***会将XML中的下拉复选插件类型(suggestManyDirectory)注册到***中作为实例化下拉复选插件的模板,载入一个插件类型分为4步:
将插件类型名(suggestManyDirectory)4-1载入4-2;将处理插件的方法(handler-class)4-3载入;将显示插件的模板属性(property)4-5载入4-6;将插件类型的配置信息(configuration)4-7通过方法4-8载入。4-8将分别将标题(title)4-9载入4-10,将支持的模式(supportedModes)4-11载入4-12,将插件的字段组织形式(list)4-13载入4-14,将字段支持的类型(supportedTypes)4-15载入4-16,将插件包含的显示位置列表(categories)4-17载入4-18,其中的document意味着在文档管理界面使用该插件,将插件默认的浏览布局4-19(包含“宽度suggestion_width”等部件)载入4-20,将插件默认的编辑布局4-21(包含浏览布局的部件及编辑用的“必选required”等部件)载入4-22,可以看到编辑布局4-22的部件数[19]远多于浏览布局4-20的部件数[7],将编辑状态下的默认值(defaultValues)4-23载入4-24。最后用注册插件类型(registerWidgetType)方法将定义好的插件类型描述符(desc)4-25注册到默认的jsf类别(category)4-26中:从插件类型描述符4-29中提取配置信息(configuration)以外的三项组成一个轻量级的插件类型4-27并将其载入类别为jsf的类型注册表(typeReg)4-28中;再将插件类型描述符(desc)4-29载入类别为jsf的插件类型定义信息注册表(defReg)4-30中。
如图5所示,***会根据下拉复选插件类型(suggestManyDirectory)实例化一个能选择主题(subjects)的下拉复选插件:
5-1为该主题(subjects)下拉复选插件具体的xml配置信息,当客户加载的页面包含该插件时***会根据该插件的注册信息(插件的注册步骤同图4中的插件类型注册步骤)和运行环境临时计算生成一个插件。***先通过当前布局的模式(layoutMode)5-2取得该插件的模式(wMode)5-3,如果插件模式等于隐藏(HIDDEN)5-4的话返回null,即不生成该插件。***用getRequired方法5-5判断该插件是否为必选插件,它将先用getProperties方法5-6取得该插件的当前状态下的属性,该插件的所有属性(properties)5-7为一个以any作为键值的哈希表,它取自于xml中的属性标签(properties)5-8,***先提取该插件在任何状态下(any)的属性5-9,该属性为5-7中any键值对应的内容,在提取当前插件模式(mode)5-10下的属性5-11,该属性为空,最后再将5-9和5-11载入5-12组成插件当前状态下的属性并返回getRequired方法5-5,如当前状态下的属性包含必选(required)属性5-13则返回必选键值对应的内容(required=true就返回true)来判断当前插件是否为必选插件。***取得该插件的类型(wType)5-14,通过getStoreCategory方法5-15来调用该插件的类别,没设置类别的话会用getDefaultStoreCategory方法5-16返回默认的jsf类别5-19,将该值作为参数5-17来执行获取插件类型定义信息getWidgetTypeDefinition方法5-18,该方法会根据插件类别5-19来获取jsf类别的插件类型定义信息注册表5-20,即图4中注册了插件类型的注册表(defReg)4-30,再根据该插件的类型名5-21(同5-14中的suggestManyDirectory,插件类型名4-1)获取该插件的类型定义信息5-22即图4中注册的下拉复选插件类型4-29。通过getDefaultPropertyValues方法5-23来获取默认属性,5-24为插件类型的默认属性,它是由xml中的默认值标签(defaultValues)4-23定义的,提取其任意模式下的属性5-25及插件当前模式5-26下的属性5-27组成插件类型默认属性,将插件类型默认属性5-28和插件属性5-29分别载入生成插件的总属性(props)5-30。5-31为插件类型的默认编辑布局(同4-21),它为最少字符(minChars)属性5-32赋予默认值,subjects插件继承了该属性5-33,插件类型提供了选择目录名(directoryName)5-34属性,subjects插件为该属性赋予110nsubjects值5-35规定该下拉复选插件选择110nsubjects目录下的词汇,插件类型为宽度(width)属性5-36赋予默认值400,subjects插件用300覆盖了该属性5-38。就这样,subjects插件以图4中的下拉列表插件类型为模板,引用其默认架构并添加了新的扩展生成了选择主题的下拉列表插件。
如图6所示,***将插件的字段及属性变量暴露给了前台:
取出插件的类型名6-1和插件的类型类别6-2,用getWidgetTypeHandler方法6-3来取得插件的处理器,该方法会用getWidgetType方法6-4取出插件类型,即通过插件类别6-5获取类别为jsf的插件类型注册表,该注册表为图4中只包含处理方法和属性模板的轻量级插件类型注册表4-28,再通过类型名6-7取出插件类型6-8,即图4中的轻量级插件类型4-27,通过getWidgetTypeClass方法6-9取出该插件类型6-8的方法类6-10(同4-3),用该方法类实例化一个处理器6-12,再把插件类型6-8中的属性模板6-11(同4-5)***处理器,用该处理器中的getFaceletHandler方法来暴露插件变量。用getTemplateValue方法6-13获取模板,若插件类型的模板不为空则获取6-14,否则获取插件的模板6-15。生成一个包含环境变量ctx和标签信息tagConfig的表现层处理器6-16,用它的getTagAttributes方法6-17创建标签属性,bindFirstFieldDefinition布尔值6-18为true的话会把第一个字段的值绑定到标签的value属性上,6-19为插件的字段列表,由插件xml信息的fields标签6-20定义,取列表的第一个值(field)6-21,再用createExpressionString方法6-22把该值改成expression语句,该方法会对不同的字段格式进行不同的处理,这里它用:把字段分割成数组6-23再将其组成6-24中的格式,最后用#{}将6-24括起来变成6-25中的样式,用字段值6-25和键值value字符串6-26作为createAttributes方法6-27的参数来创建标签属性,该方法将引入当前标签的具***置6-28,即layout_default_template模板中在73行77列结束的<nxl:widget>标签范围以内,所生成的标签属性如6-29所示。用getAttributes方法6-30取得属性的标签属性,它将插件的每条属性6-31,即xml信息中属性property标签6-32中的内容,取其键值(key)6-33,用样式#{%s.properties.%s}把属性转化成6-35中的三级节点,它是一个引用因此不会保存在缓存中,不会被ajax刷新,将键值6-34和引用6-35输入方法6-27会创建标签属性6-36。根据(id)6-37为标签生成一个id属性,再用6-14中的模板生成一个template属性(这两个属性都是用方法6-27生成的)。接下来计算要渲染的变量,让模板中field_0、field_1格式的字段值可用,取出标签中键值为value的属性6-38,即我们第一个创建的标签属性6-29(其localName和qName都为value)中的取值(value=#{value[’dc’][’subjects’]}中等号右边的内容),再取出需要暴露的变量名(field)6-39(还要暴露filed_0,fieldOrValue等),最后用createValueExpression方法6-43为其包裹EL标签,添加功能映射,6-40为封装的表达式,6-41为封装的变量映射,6-42为预期的Object对象。再提取插件的每条属性6-44,据其键值6-45进行格式转化产生该属性需要暴露的变量名(widgetProperty_minChars)6-46,从minChars标签属性6-36中取值(value=#{widget.properties.minChars}中等号右边的内容),最后用方法6-43依次封装每条属性。
如图7所示,***通过suggest_many_directory_widget_template.xhtml文件在前台显示插件,该文件在插件类型的属性标签4-5中定义,插件暴露变量时用6-14作为值生成了一个template标签属性,该属性为显示复选下拉插件的模板信息:
xhtml先对插件状态进行判断,此处当插件为浏览或编辑状态时对插件进行显示,先在帮助标签7-1中赋予label.suggestion.help.minChars对应的中文信息。再显示标签框(valueHolder)7-2,标签框中的值(value)7-3为图6中暴露的field_0变量,它对应的表达式6-40为#{value[’dc’][’subjects’]},其中dc为都柏林架构(dublincore)1-7的前缀,subjects对应着架构1-9中的subjects属性,其类型为一个字符串列表,存储了该文档的都柏林架构中的主题(subjects)属性7-3,7-4定义了本标签框是否必选,由于该插件的属性集5-8中不含有必选(required)5-13,因此该插件非必选,即框前没有红色*标志。最后显示标签框中的标签信息7-5,通过resolveMultipleDirectoryEntries方法7-6获取将显示的标签条目:先获取目录服务(directoryService)7-7,该服务包含了所有注册的目录,通过目录名7-8(在5-35中定义该插件的目录名为110nsubjects)取出具体的主题目录7-9,即图2中定义的110nsubjects目录2-1,根据该目录建立会话7-10,会话除了包含该目录(directory)外还包括架构7-11,表7-12(即3-6中根据架构建立表),主键7-13(它取自目录的xml信息2-13,被后置SQL创建语句3-14设定为该表的主键),存储的字段名7-14,会话的标志(sid)7-15,字符串匹配类型7-16(用于搜索数据库时进行模糊匹配,subinitial会对搜索字符的开头进行模糊匹配),是否自增7-17(定义于目录的id自增标签2-18),sql连接7-18(根据目录数据源标签2-5产生的到postgresql数据库的连接信息2-6),最终产生会话(session)7-19,可以通过该会话对数据库进行查增删改等操作。根据架构名7-20(同2-8)取出架构7-21,再取出用户的区域7-22,把这两个参数塞入getLabelFieldName方法7-23来获取标签名,没设置labelFieldName的话会用7-24中的label作为默认值,若db10n(插件属性集5-8中的第二条属性)7-25为true则在默认值后加上“_”和区域7-22组成7-26作为判断显示属性(如“电影”)的字符串。从7-27(即从前台传来的标签变量7-3)中取出一条7-28并用resolveDirectoryEntry方法7-29将其做成前台可用的JSONObject标签对象,没设置分隔符的话用默认的“/”7-30,将传来的参数7-31“/”前的部分取出作为条目标志7-32,在会话7-19中根据条目标识提取出完整的条目信息(包括id,label_fr,obslete等)7-33。依次提取架构7-21中的每一栏目7-34并取出其栏目名7-35,在7-33中取出该栏目名所对应的栏目值7-36,生成一个由栏目名7-35和栏目值7-36组成的元素并将它加入标签对象中,如果栏目名与显示字段7-38相等(该显示字段是7-26中根据默认值和区域组合的label_en),如果是否翻译7-39(图5中插件xml信息的<translated>标签中的内容)为true,则在总翻译文件7-42中提取该栏目值(label.directories.subtopic.cinema)7-40所对应的翻译内容(“电影”)7-41,生成一个由显示字段(displayLabel)7-43为键值翻译内容(“电影”)7-41为内容的元素并将其加入到标签对象7-44,若标签包含废弃(obslete)7-45(架构2-8中倒数第二个元素就是废弃,其默认值是0)且废弃的值大于0,则对该标签对象添加警告信息7-46,被打上警告信息的标签显示时会有警告提示7-47,再生成一个以计算ID(computedId)7-48为键值以该方法的输入参数7-49为内容的元素并把它塞入标签对象,最后返回该标签对象7-50,将每个标签对象都加入将显示的标签组7-51中并返回给xhtml中的7-6作为标签信息的值,其显示结果如7-52所示。最后用encodeParamtersForDirectory方法7-53对插件属性和参数进行编码以至前台的select2.js文件可以提取到它们,取出插件的属性集7-54并依次提取其每条属性(例如宽度)7-55,将其键值7-56和内容7-57写入JsonGenerator中,这样前台生成插件时select2.js文件会提取到该宽度属性7-58并为插件加载该样式,加载前插件宽度如7-59(一个***提供的默认宽度)所示,加载后插件宽度如7-60(300px)所示。在设置一个操作Id(operationId)7-61,内容为Directory.Suggestions7-62的参数7-63,并将其加入JsonGenerator,该参数将为插件生成关于110nsubjects的下拉列表如图8所示。
如图8所示,***获取了操作标识符(ID)8-1为Directory.Suggestions的方法类并运行了该操作的默认执行方法run,它会获取110nsubjects目录的所有词条并通过迭代的方法将它们生成一个JSONAdapter树:
***会先通过目录名(110nsubjects)8-2在目录服务中获取具体的目录(directory),通过目录获取会话,通过目录获取架构名8-3并用它来获取具体架构,用方法7-23计算出当前环境下的显示字段8-4,以废弃(obsolete)8-5为键值“0”为内容建立过滤器8-6,以“id”为键值“asc”为内容建立排序准则8-7,最后通过一个连接到postgresql数据库中110nsubjects表的会话8-8(具体内容见7-10),发起一个以过滤器8-6和排序准则8-7为条件的查询操作8-9:用一个<字符串/对象>格式的过滤器映射表(filterMap)8-10获取过滤器8-6,依次提取8-10中的每条过滤项8-11,取其值8-12,取其栏目8-13,用栏目中的QuotedName属性8-14(即带双引号的obosolete)作为限制条件的左侧,“?”作为右侧,“=”作为符号,用左侧附加符号组成8-15,再附加右侧组成一条完整的限制条件8-16,组合搜索条件Select,设置搜索内容(setWhat)为*,设置搜索地址(setFrom)为表名8-17,设置限制条件(setWhere)为8-16,在转化8-7的格式生成一个(“键值”内容)的SQL排序语句8-18,得到的搜索条件如8-19所示,用它产生搜索语句8-20,创建一个预处理执行语句ps并为其绑定参数得到8-21,执行完该查询语句即可按id的顺序获得110nsubjects表中的所有非废弃(“obslete”=0)的词条并将其返回entries,该***就是这样通过传入过滤器等参数自动组建SQL语句的。执行一个带两个参数的JSONAdapter方法8-22生成一个根节点,为其赋值会话、架构,生成一个哈希表结构的children变量,其根节点判断条件isRoot为true。再根据刚搜索到的词条集(entries)8-23,依次取出每个词条(entry)8-24,用带3个参数的JSONAdapter方法8-25生成一个非根节点:依次提取架构中每个栏目8-26的键值和内容组成元素***JSONObject对象,若键值等于“label_en”8-27则设定其为显示字段,若translatedLabels为true则翻译字段,若废弃字段8-28存在且大于0就添加废弃提示,最后生成对象8-29(生成对象的详细步骤见7-34至7-50)。通过isLeaf方法8-30判断生成的节点是否为子节点:它用“parent”8-31作为键值用节点Id(architecture)8-32作为内容组成一个过滤器8-33,用会话发起查询,由该过滤器生成的SQL查询语句如8-34所示,它将选择110nsubjects表中所有父节点为“architecture”的词条,如果搜索结果不为空的话布尔值isLeaf就是false,意味着不是子节点。不是子节点的JSONAdapter(如8-35中的“艺术”为“建筑”的父节点)会在isLeaf判断后跳过程序,是子节点的JSONAdapter(如8-36中的“建筑”为子节点)会通过push方法8-37***到根节点中。***过程是个迭代的过程,将“建筑”8-38***时会先取其父节点Id“艺术”8-39并判断父节点是否为空,如果非空的话看看当前对象(被***的节点)是否为“建筑”8-38的父节点,用父节点“艺术”8-39与当前节点的Id(getId)8-40比较,由于当前节点是根节点,其父节点不存在判断肯定失败,既然当前节点不是父节点那就创建一个父节点,接下来就取“建筑”的父节点“艺术”的词条8-41并用创建非根节点方法8-25生成一个新的“艺术”JSONAdapter对象8-42,用push方法8-44把“建筑”8-43***新建的父节点“艺术”8-42中,取建筑的父节点“艺术”8-45,父节点不为空,用“艺术”和当前节点的Id(getId)8-46判断,由于当前***节点就是“艺术”,其id也是“艺术”所以判断通过,既然当前节点就是父节点我们就在这***“建筑”,接下来通过mergeJsonAdapter方法8-48融合“建筑”8-47,当前“艺术”8-49由于是新建其孩子为空,从孩子(为空)中取“建筑”8-50的显示字段,其结果(found)8-51肯定也是空的,判断不成立,既然孩子里没有“建筑”就***“建筑”,在当前“艺术”节点的孩子中***以显示字段“建筑”为键值以“建筑”8-47节点为内容的元素,其结果如8-53所示,将当前被***节点“艺术”8-54返回到8-42此时在根节点8-55中用push方法8-56***返回的“艺术”,此时的***节点为“艺术”8-57,由于当前节点(根节点)的父节点8-58不存在判断失败,既然根节点已经没有父亲了就在根节点中融合“艺术”,用mergeJSONAdapter方法8-60融入“艺术”8-59,当前节点(根节点)8-61的孩子为空,判断失败,既然根节点没有“艺术”就在孩子中***这个“艺术”8-62。再在根节点中***“艺术史”8-64,同样是先建立一个空节点“艺术”并在其中融入“艺术史”8-65,以“艺术史”8-66的显示字段为键值以“艺术史”节点8-66为内容生成一个元素并***新“艺术”的孩子中如8-67所示,再在根节点中***带有“艺术史”的新“艺术”,在根节点8-68的孩子中找显示字段为新“艺术”的节点,由于根节点中已***一个包含“建筑”的旧“艺术”8-69,因此找到了判断成功,既然根节点已含有“艺术”节点,只需将新“艺术”的孩子融入就行了,所以将新“艺术”8-70中的“艺术史”8-71融入刚找到的旧“艺术”8-72。程序运行完后将得到一个由JSONAdapter对象组成的词条树,其根节点8-73包含了各个一级词汇(如艺术),每个一级词汇8-74下又包含若干个二级词汇(如建筑)。
如图9所示,***通过(图中间的)javascript将图8中的词汇树组成一个前台可以显示的元素树(图右上角),并为各元素添加css样式(图左下角):
9-1是图8中生成的词汇树,它包括了“艺术”等6个一级词汇,9-2是将要容纳树的前台元素(也可以说是根元素),9-3是一级词汇的纵深,其值为0,可以通过9-4的方法为当前纵深下的词汇排序,在9-1中依次取出每个词汇9-5如“艺术”,其禁用(disabled)9-6变量为false,如果非禁用且含有id的话该元素可选择,从9-5可看出“艺术”没有id属性所以其可选择(selectable)9-7变量为false,如它有孩子的话(可以通过9-8看出它有10个孩子)设定其复合变量为true。建立一个<li>标签的节点9-10作为“艺术”元素,其纵深样式值9-11为0,由于它是不可选9-7为其打上select-result-unselectable样式9-12,由于它是复合元素9-13为其加上select2-result-with-children样式,可以在9-10对应的前台元素(图右侧很长的一行)中看到这些样式。为“艺术”元素添加一个显示标签9-14,取出经过格式处理的显示字段9-15并将它加到显示标签9-14中,再把显示标签9-14加到“艺术”元素9-10中,由于该节点是复合节点,还要在其后为其添加一个子容器9-16来容纳“艺术”下的二级词汇,迭代使用populate方法9-17将“艺术”的孩子9-18填充到“艺术”的子容器9-19(同9-16),并将其纵深9-20加1。依次取出“艺术”的孩子中的一项9-21“建筑”,由于它非禁用且含有id属性9-22故其可选择变量9-23为true,由于“建筑”为叶子节点没有孩子所以其复合变量9-24为false,建立一个<li>标签9-25作为“建筑”元素,其纵深值9-26为1,由于它可选择9-23为其加上select2-result-seleetable样式9-27,在为“建筑”元素添加显示标签9-28并在显示标签上加入显示内容9-29,由于“建筑”不是复合元素9-30不添加子容器,再将“建筑”词条的全部属性信息9-31塞入元素以备选中时存储用,最后将新生成的“建筑”元素9-32塞入“艺术”的子容器,当“艺术”填充完全部子元素后再将新生的“艺术”元素9-33塞入根元素,当把所有一级词汇都填充到根元素后一颗前台(下拉列表)显示用的元素树就做好了。***为每个元素都添加了select2-result样式9-34,为每个显示标签都添加了select2-result-label样式9-35,它们为元素和标签设置了基本的内外边距等样式,对于那些有select2-result-with-children样式9-36的复合元素,将其设置为粗体如9-37所示,对于那些包含在子容器select2-result-sub中的标签9-38,为其select2-result-label标签样式添加20px的缩进如9-39所示,且被包含的子容器树越多(多级词汇)其所尽量就越大,当鼠标移到下拉列列表中的某项词汇时会用方法9-40来高亮并选中它,该方法只会返回那些可选择9-41且非已选非禁用的词汇,由于“建筑”包含select2-result-selectable样式故可以高亮并选中它9-42,而“艺术”既无法高亮也无法被选中。
如图10所示,***提取插件的XML信息并将其生成一个只包含组件最上级节点的注册信息实例:
首先提取bareproject-1.0-SNAPSHOT.jar中的btion-contrib.xml文件地址10-1,该xml文件包含了下拉列表插件类型suggestManyDirectory及下拉列表插件subjects的具体xml信息,通过createRegistrationInfo方法10-2把该xml文件中的内容转化成一个注册信息:先通过文件地址10-3(同10-1)运行getStream方法10-4,该方法将打开一个到10-3的连接并返回一个从该链接读取到的输入流作为信息源10-5,对信息源10-5执行扩展变量(expandVars)方法来把其中的变量扩展为配置信息(通常是.conf文件)中该变量所对应的具体数值:它提取配置信息中的所有属性10-7(通常为网站网址、数据库端口等***配置信息),把属性10-7赋给TextTemplate方法的全局变量(vars)10-8,根据样式10-9(该样式意味着提取一个“${键值=内容}”形式的字符串,其中键值只能为字母数字等)组成一个针对数据源的匹配器m,当匹配器10-10找到与10-9相匹配的内容时,取出其键值10-11,通过取变量getVariable方法10-12,在包含属性的全局变量10-13(同10-8)中找到键值10-11(db.port)所对应的内容10-14(5432),再在数据源10-5中把该特定格式的变量替换为其在配置文件中对应的内容就完成了变量扩展10-15,该例子在subjects插件的显示名(label)10-16中设置了数据库端口变量${db.port},在扩展变量过程中将该变量替换为了实际的数据库端口值5432,并用5432作为插件的实际显示名10-17。然后把扩展后的数据源编码为一系列字节并存储到一个新的字节数组中10-18。对字节数组10-18执行createRegistrationInfo方法10-19将其创建成一个注册信息:通过方法10-20来处理由输入流10-18得到的xml文件:定义一个用于获取解析器的工厂10-21,再通过工厂定义一个将xml文档转化成dom文档的解析器10-22,通过10-22的parse方法10-23将给出的输入流10-18内容解析为一个XML文档并且返回一个新的DOM文档对象10-24,可以通过DOM文档对象10-24的getDocumentElement方法10-25方便地直接访问该文档对象的孩子节点。通过带3个参数的loadAll方法10-26来处理给定的DOM元素10-24并返回该元素的一列顶级可映射对象:该DOM元素10-24的名字为组件(component)10-27,通过newInstance方法10-28创建该组件的实例,依次处理该组件成员集10-29中的每一条10-30,service意味着该组件暴露的服务,name意味着组件名(biction.xml),require意味着该组件依赖的其他组件,其中的extension成员10-31意味着该组件贡献的所有扩展,如我们前面定义的subjects插件。在成员处理成方法(process)10-32中,先取其值10-33,取出其映射路径中的名字10-34(extension)并找出所有名为extension节点10-35,寻找节点方法如下:依次取出biction.xml文件中的所有节点,取出的第一个节点10-36为一个空行文本节点,由于它不是元素节点10-37,取出其下相邻的节点10-38,由于该节点为元素节点10-39,如其名10-40为extension,则用newInstance方法10-41创建该extension扩展节点10-42的实例。依次处理10-43扩展节点的每个成员,包括扩展目标(target)10-44即实现该扩展的具体方法类,及扩展点(point)即该扩展为方法类(target)中的哪一个部件,通过取值方法10-45获取该扩展节点(extension)的扩展目标(target)10-46属性值,它将调用取节点值方法10-47来获取给定基础节点(extension)下相对路径为target的节点值,基础节点如10-48所示,可以看到它包含point和target两个属性,当要取的相对路径中属性10-49不为空时,则从基础节点中提取该target属性10-50,若相对路径中没有属性则提取该基础节点的文本信息10-51(比如说明文档)。最后通过方法10-60把刚获取的target值赋到实例中的对应位置10-52,即在biction.xml组件10-53中的extension扩展实例10-54中的target属性10-55上赋值10-56,10-56中的WebLayoutManager为扩展网页布局内容的服务接口,根据扩展点point的不同,可以扩展widgettype插件类型、widget插件、layout布局等。赋值完扩展(extension)后再将所有的扩展实例10-57赋值到10-58组件中,最后得到一个从XML文件生成的注册信息实例10-59,它包含了组件biction及其最上级子节点,图11中将讲述该注册信息中的扩展是如何根据依赖关系被挂起及实现。
如图11所示,***将依赖条件不成熟的扩展框架放入等待特定依赖的队列中并在依赖条件成熟时加载该扩展框架:
11-1为图10中生成的注册信息,它包含了bicion组件的所有最高级节点,包括组件名11-2及扩展11-3。用方法11-4注册该实例,在组件注册表reg中添加该实例11-5:先在其中的组件(components)11-6中添加一个以实例名(name)11-7(同11-2)为键值以实例(ri)11-8(同11-1)为内容的映射,再激活11-9该实例:取出该注册信息实例的所有扩展11-10并用registerExtension方法11-11依次注册每个扩展11-12:该扩展为下拉复选插件类型suggestManyDirectory,其扩展目标(target)为WebLayoutManager,其扩展点(point)为widgettypes,获取用来实现该扩展的目标组件名11-13,并在组件注册表(reg)11-14的组件(components)11-15中寻找名为WebLayoutManager(由11-13获取)的目标组件注册信息,可以看到在组件的列表中包括了刚刚在11-6中添加biction组件11-16,如果取得的目标组件注册信息11-17不为空就用WebLayoutManager来实现该扩展,否则将该扩展添加到挂起扩展(pendingExtensions)中等待WebLayoutManager的队列中:在挂起扩展11-18中寻找名为WebLayoutManager的等待队列,若结果11-19为空则创建一个空的扩展集11-20,并在挂起扩展中加入一张以WebLayoutManager为名,以空扩展集11-20为内容的哈希表,在空扩展集11-21中加入下拉复选插件类型11-12。再用方法11-11注册该注册信息实例的下一个扩展11-22:该扩展为下拉复选插件subjects,由于其扩展目标的组件还未被加载到组件注册表reg中,只能将其加入等待队列:在挂起扩展11-18中寻找名为WebLayoutManager的等待队列,找到刚刚创建的包含下拉复选插件类型的扩展集11-23,在扩展集11-21中加入新的等待WebLayoutManager的挂起扩展11-24(同11-22)。最后获取等待biction组件的扩展,在挂起扩展pendingExtensions中获取名为(biction)11-25的等待扩展集11-26,由于其为空(即挂起扩展中没有等待bction的扩展)跳出程序,否则用biction依次实现等待扩展集11-26中的每条扩展。当激活组件WebLayoutManager时,在挂起扩展pendingExtensions中获取名为(WebLayoutManager)11-27的挂起扩展队列11-28,remove方法在挂起扩展中删除队列的同时将队列赋给11-28,可以在挂起扩展队列11-28中看到所有等待WebLayoutManager的挂起扩展,包括先前注册的biction中的扩展,依次提取11-28中的每条扩展,例如下拉复选插件subjects的扩展11-29(同11-24),用获取配置方法(loadContributions)11-30取出该插件的配置参数,方法11-30将先取出该插件扩展点(point)11-31中的值“widgets”再在注册信息实例11-39(WebLayoutManager)中用获取扩展点方法(getExtensionPoint)11-32获取名为“widgets”11-33的扩展点实例,11-34为WebLayoutManager组件注册的扩展点集合,包括插件、插件类型、布局等扩展点,依次取出每个扩展点的名字看其是否是“widgets”11-35,11-36为WebLayoutManager组件中插件(widgets)扩展点的XML信息,它用插件描述符(WidgetDescriptor)作为该对象的实现类方法11-37,最后找到并取出了WebLayoutManager中名为“widgets”的扩展点实例(xp)11-38。若扩展点实例11-38不为空且其描述符不为空,则通过扩展点实例11-40(同11-38)提取下拉复选插件扩展(xt)11-41中的配置参数11-42并把它赋给11-41中的contributions项,如图可看到当前的扩展11-41中的配置参数contributions项为null,这是因为该扩展只是biction中的一个最高级节点,它只包含了扩展11-43的target和point属性,图12中将讲述如何获取最高级节点11-43的具体配置参数11-44并将其注册。
如图12所示,***通过扩展点的描述符取出扩展在XML文件中的具体配置信息,用配置信息将最高级节点填充为完整的扩展节点,并依据扩展点的不同将其分类注册:
接上图11,***为了在激活active方法中获取12-1插件扩展xt的配置参数,它需要找到扩展所对应的扩展点实例并通过它获取12-2扩展的配置参数,若扩展点实例11-38中的contributions不为空12-3(其中包含了插件描述符WidgetDescripter),则在xmap12-4(xmap由包含各种基本类型的factories,以描述符为键值xmap对象为内容的objects,以节点名为键值xmap对象为内容的roots)中注册12-5该描述符12-6:先在objects12-7中寻找插件描述符(WidgetDescripter)12-6,由于12-7为空找不到所以需要新建,检测该WidgetDescripter描述符12-9中是否含有标注12-8,若含有的话(12-15就算一个标注)通过该描述符创建一个xmap对象(xao)12-10,可以看到xao中包含ctor(构造器其值和描述符相同),klass(描述符),及members(插件的成员,即各个标注,目前为空),在(objects)12-11中以描述符klass为键值xao为内容创建一个映射对象以免以后重复创建,对xao执行scan方法12-12,它将提取描述符(目前为aClass)中的所有标注作为字段集(fields)12-13,再依次把12-13中的每个字段如name字段12-14(即描述符中的name标注12-15)通过createFieldMember方法创建为成员12-16,一个成员12-16中包括字段地址accessor(此处值为WidgetDescripter.name),相对地址path(此处值为name),类型type(此处值为java.io.String)构成。将每个成员都加到(xao)12-17的members中构成该描述符模板的成员集。再在(roots)12-18中以节点名widget为键值xao为内容创建一个映射对象以便以后通过相对路径查到该widget节点。在新创建的xmap中以环境12-19(其中包括了扩展中xml信息的实际物理地址biction-contrib.xml)和扩展元素12-20为参数用loadAll方法12-21获取扩展的具体配置信息:先取出元素12-20的名字,由于它是扩展元素其名字12-22为extension,在roots(同12-18)中查找其内容,若其内容12-23为空则查找它的孩子节点(p)12-24,由于12-24为空格文本不是元素所以取其相邻节点12-25直到找到元素节点(详细步骤见10-36至10-39),取该元素12-25的节点名12-26(值为“widget”),在(roots)12-27(同12-18)中寻找键值为“widget”12-26的内容xob(即先前创建的“xao”12-10),若内容12-28不为空,则根据插件描述符模板xao创建一个具体的描述符实例12-29:根据构造器(ctor)12-30(即12-10中的第一个节点)创建一个空的插件描述符对象12-31,对其成员集members中的每个member成员12-32(如name成员,即描述符中的name标注12-15)使用process方法12-33来赋值:该方法从biction-contrib.xml文件中取得该name元素的值12-34为subjects(具体步骤见10-45至10-51),再在成员的地址字段12-36(即12-16中的XFieldAccessor)上赋值subjects,把描述符实例12-29中所有的空白成员都赋予其在XML文件(即下拉复选插件subjects的XML信息5-1)中对应的具体内容,将其返回到方法12-2左侧的contribs即为要提取的配置参数,为插件扩展xt设置该配置参数(contribs)12-37,可以看到当前的xt如12-38所示,其contributions节点12-39不再为空(加载配置参数前contributions节点的值如11-44所示),它包含一个插件描述符(WidgetDescriptor)及刚为其各个成员赋予的成员值12-40,用WebLayoutManager组件(component)中的注册扩展方法12-41注册该扩展:首先取出扩展的配置参数(contribs)i2-42,XML中可以在一个插件扩展(即contribs)内加入多个插件,如主题(subjects)下拉复选插件、地理下拉复选插件等,选出其中的每一个扩展(contrib)12-43及扩展点12-44,用registerContribution方法12-45注册该具体扩展:若扩展点12-44等于12-46(即插件类型widgettypes),就用插件类型描述符实例化该扩展12-43并用描述符的getWidgetTypeDefinition方法12-47取得插件类型定义信息,最后用registerWidgetType方法注册该定义信息(具体步骤见图4)。若扩展点等于(WIDGETS_EP_NAME)12-48(即插件widgets),用插件描述符12-49实例化该扩展并用该描述符的getWidgetDefinition方法(该方法用WidgetDefinitionImp方法根据扩展的配置信息创建一个插件定义信息)获取插件定义信息,最后注册该定义信息。
如图13所示,可以通过修改XML中的配置信息来快速灵活地定制插件:
下拉列表插件subjects原始的xml配置信息如13-1所示,其对应的前台界面如13-2所示,它是通过WebLayoutManager方法13-3中的widget描述符13-4提取注册的插件定义信息,被赋予了下拉复选插件类型13-5的处理方法类和前台显示模板,可以通过对插件类型中特定布局5-31的不同部件设置参数来配置出千姿百态的下拉复选插件。13-6为插件名,它好比插件的Id,在后加载的补丁中加入同名插件就会覆盖掉原来的subjects插件,加入不同名插件就会添加一个新插件。13-7为插件的标题,将<label>标签中的内容换成13-8(label.dublincore.coverage字段对应的翻译为“地理范围”)就把插件的标题改成了地理范围。13-9为标题提示,将其中的内容换成13-10就将标题提示也改成了地理范围。13-11为是否翻译,它为true的话会在***的总翻译文件中查找该字段所对应的翻译内容(详情见7-39至7-44),若将其置为false就会将插件的所有字段都显示成未翻译的模样13-12。13-13为插件将显示该文档的什么内容,“dc:subjects”意味着插件将显示当前文档都柏林架构数据(dc为dublincore的前缀1-7)名为subjects的字符串列表1-9,若将其换成dc:zhishi属性13-14(在都柏林架构中自定义的字符串列表数据架构“学科知识”),将在“内容主题”中显示“学科知识”中的标签“数据整理方法”13-15,由于在subjects调用的主题词汇树(取自110nsubjects)中找不到该路径(zhishi_001_004)所对应的词汇所以只显示其路径且加上了警告标志。13-16为插件设置宽度(详情见7-55至7-60),将其值改成100将明显缩短其宽度13-17。13-18为显示下拉列表所需的最少字符数,默认为0即点击输入框后直接显示下拉列表,若将其值改为2,将在点击输入框时显示“请再输入2个字符”13-19,当输入两个字符(如“艺术”)13-20后将显示所有包含输入字符的词汇(如“艺术史”)。13-21为隐藏下拉列表提示,由于下拉复选插件通常不需输入字符故默认为true,将其值改为false可看到该提示13-22,除此以外还有用来隐藏标题提示和空白提示的部件。13-23为插件显示的目录名,***将在数据库中搜索目录110nsubjects的所有词汇并以树的形式将其显示到插件的下拉列表(详情见图8图9),若将其改成110ncoverage(该目录中存储的是地理词汇)则将生成一张用以选择不同洲不同国家的下拉列表13-24,由于在目录110ncoverage生成的词汇树中找不到“电影”这个主题词汇的路径,故只显示其路径“art/cinema”13-25(通过路径查找词汇显示标签的详细步骤见7-27至7-44)。若在插件的属性集中加入required部件13-26(可以在下拉复选插件类型的编辑布局4-21的第一行看到该属性)并将其值设为true,则插件将成为必填插件,其标题后将有一个红色的*标志13-28,且输入框中内容为空时保存文档会出错。13-29为插件输入框的空白提示部件,设置label.security.search的话会会用“搜索用户或群组”13-30来取代默认的空白提示“请输入”。13-31为区域化部件,值为true的话会获取浏览器的区域7-22并将其添加到显示字段后用以显示该词汇在当前区域下的翻译内容,如label_en会显示该词汇的英文翻译,label_cn会显示该词汇的中文翻译(添加区域具体步骤见7-22至7-26),将其设为“false”13-32就不会为显示字段添加诸如_en之类的区域后缀,13-33为显示字段部件,当不添加该部件或该部件内容为空时会取其默认值“label”7-24,若将该部件的值设为id并且将db110n设为false(否则会变成id_en),则将在输入框中显示标签的id内容13-34。13-35为是否可选父节点部件,13-43为向词汇树加入JSONObject词汇的方法,若当前词汇为子节点13-44将直接返回该词汇,如9-21“建筑”词汇,由于它是一个完整节点包含id节点9-22,因此selectable变量9-23为true它是可选的。对于非叶子节点将根据canSelectParent部件13-45的值来决定其节点构成,默认情况下13-45为false,即跳过判断,创建一个只包含显示字段13-46的节点并在其后加入其所有孩子节点,如9-1“艺术”词汇,可以看到它只包含displayLabel和children两个节点,由于其不包含id节点selectable变量9-7为false所以父级节点默认不可选,若将canSelectParent部件的值设为true将执行13-45判断,返回该完整的节点13-47并在其后加入其所有孩子节点,由于完整的“艺术”词汇节点包含id节点13-48故它是可选的13-36,如此一来就可通过修改subjects插件XML配置信息中的canSelectParent部件的布尔值来决定是否可在下拉列表中选择父级词汇。13-37为显示忽略词汇部件,通过displayObsleteEntries布尔值13-49判断是否在下拉列表中显示已被忽略的词汇,默认情况下displayObsleteEntries值13-50为false,将运行条件判断中的程序建立一个内容为{obsolete=0}的过滤器13-51,在通往数据库110nsubjects表的会话8-8中,以该过滤器13-51为参数发起查询操作8-9,查询时会将过滤器的内容组建为SQL中的一个条件语句(8-10至8-16),最后生成的SQL查询语句如13-52(同8-21)所示,,它用WHERE“obsolete”=0条件语句过滤掉了所有已被废弃(obsolete不为0)的词汇,如当已废弃“电影”词汇时就无法在下拉列表中再看到“电影”词汇13-37,若将displayObsleteEntries部件的值改为“true”13-38,此时13-53为true,将跳过条件语句中的程序,过滤器13-54中的内容为空{},最终生成的SQL查询语句如13-55所示,可以看到它没有WHERE“obsolete”=0这个过滤条件,没有过滤掉已被废弃的“电影”,故可在13-38中看到该已被废弃的“电影”词汇,连同其后的警告标志。也可以通过XML配置文件为该subjects插件配置特定样式,如(containerCssClass)13-39为边框样式部件,在其中设置select2-highlighted(即高亮样式)的话就可以看到输入框的底部13-40成高亮状态,(dropdownCssClass)13-41为下拉列表样式部件,若将其值设为select2-highlighted的话整个下拉列表13-42都会成高亮状态。如上就是一个通过XML配置插件的具体例子,可以看到即使没有任何编程经验的员工,只需要修改XMl中的某个参数(如将一个部件的false改为true)就等同于在程序中做了一次判断,进而影响到显示标签的结构、搜索语句中的过滤条件等诸多因素,员工可以在XML中随意地修改提示文本、选择词汇的显示内容、***喜欢的边框样式等,这些操作都将以插件定义信息的形式被注册到***中并深入地影响插件的表现及功能。
如图14所示,***将都柏林(dublincore)布局注册到***中:
14-1为该布局的XML扩展信息,可以看到它的扩展目标为WebLayoutManager扩展点为layouts,通过其配置信息可看到该布局名14-2为dublincore,它调用的前台模板14-3为/layouts/layout_default_template.xhtml,在它的行列表14-4中包含了该布局要在前台显示的插件,可以通过增删行(row)来增删将在前台显示的插件,例如它在第二行14-5将下拉复选subjects插件***了布局。该布局是通过WebLayoutManager中的注册扩展14-6方法注册的,当扩展的扩展点14-7等于“LAYOUT_EP_NAME”14-8(即layouts)时,就用布局描述符(LayoutDescriptor)14-9将其实例化:可以看到一个布局的架构包括名字14-10、前台显示模板14-11、以布局行描述符为单位的行数组14-12和栏目数组14-13、以多个插件描述符为内容的插件哈希表14-14、以多个属性描述符为内容的属性哈希表14-15、以及类别14-16。通过getLayoutDefinition方法14-17获取布局定义信息:若扩展的前台模板14-18(同14-3,意味着在任何模式下前台模板为layout_default_template.xhtml)不为空就在哈希表ctemplates中加入该模板,通过getRows方法14-19取出其行列表:该方法将先根据行列表长度(14-4中的row数)建立一个空的行数组14-20,再对扩展行列表14-4中的每一行依次使用getLayoutRowDefinition方法14-21来获取其布局行定义信息:布局行描述符中包含了行名name、行中插件widgets、是否总是显示该行alwaysSelected等多个标注,若行中插件14-22不为空根据行中的插件数创建一个空的插件参考(cwidgets)14-23,再将行中的插件依次***插件参考14-24,可以看到插件参考的每个元素只包括类别和插件名,用LayoutRowDefinitionImp实例化一个布局行定义信息(clone)14-25,它包含一个值为false的alwaysSelected(总是选中此行)14-26,值为true的selectedByDefault(默认选中此行)14-27,以及刚创建的插件参考14-28。将布局行定义信息(clone)返回给4-21作为行数组的元素crows[i],当填完行数组所有行后将其通过getRows方法14-19返回到布局描述符的行数组(crows)14-29中,其内容如14-30所示,包括多个布局行定义信息实例。若扩展的自定义插件(widgets)14-31不为空将其输入到哈希表cwidgets中,由于14-1扩展的配置信息中没有<widgets>标签故14-31为空{}。通过LayoutDefinitionImpl方法生成一个布局定义信息14-32,可以看到该布局名14-33叫“dublincore”,其行列表14-34包含了5行(为了省版面14-4中只画了其中两行),以及它的前台模板(templates)14-35,将生成的布局定义信息返回到14-9,通过registerLayout方法14-36注册该布局:由于该布局没有设置类别category,故取默认的类别“jsf”14-37,建立一个以“jsf”为类别的布局定义信息注册表(reg)14-38,将刚创建的布局定义信息14-39(同14-32)填入到布局定义信息注册表reg中。
如图15所示,当点击文本文档的编辑选项卡时将调用其文本类型中注册的编辑布局:
***在XML文件中为每种类型的文档都定义了默认以及特定模式下的多个布局,15-1为文档(Note)类型,在其中定义了任何(any)15-2模式下的默认布局,用于编辑页面的编辑(edit)15-3布局,以及展示文档内容的浏览(view)15-4布局,其编辑布局15-3由用于修改标题信息的heading布局15-5,用于编辑文本内容和字体样式的note布局15-6,以及用于编辑都柏林元数据的dublincore布局15-7。该编辑选项卡的XML定义信息如15-8所示,它是一个操作(action),其id为TAB_EDIT,点击该选项卡将跳转到当前服务器基础路径下相对路径为/incl/tabs/的文档编辑前台模板(document_edit.xbtml)15-9,其排序值order为20并依此大小将其排在选项栏中第二个位置,其显示标签(label)中的字段“action.view.modification”对应的翻译内容为“编辑”。15-9中先声名了一个nxl标签15-10,它是布局***使用的标签,可以用来定义展示布局和插件的帮助类标签。用nxl标签定义一个用来展示布局的documentLayout标签处理器15-11,并为其加上模式(mode)为编辑(edit)和值(value)为当前文档(#{currentDocument})两个属性,该Facelet标签处理器将渲染所有附加到当前文档编辑模式下的布局。通过方法15-12在后台程序中实例化该处理器:先传入该处理器在前台xhtml文件中定义的标签参数15-13,可以通过15-13看到该标签源于/incl/tabs/document_edit.xhtml,它是在第2行、第64列结尾的<nxl:documentLayout>标签。再通过getRequiredAttribute方法15-14获取15-13中本地名localname15-15为模式(mode)的标签属性,通过getAttribute方法15-16返回15-17(this,即当前标签处理器15-12)下的15-18(tag,即从前台传入的标签参数15-13)下的15-19(getAttributes,获取15-13中的属性)中(localname)15-20为“mode”的标签属性15-21,即document_edit.xhtml中于2行64列结尾的标签中的mode=“edit”属性,通过15-14将其返回到15-22,作为标签处理器的模式(mode),用同样的方法提取标签的其它参数,比如15-11中的value属性15-23。获取完标签参数后用apply方法15-24来应用文档中每一个当前可用的布局,通过value(即当前文档#{currentDocument})获取***中缓存的实际的当前文档15-25,即“例子文本”文本文档,可以在15-25中看到其UUID、路径和标题,通过15-25获取文档类型信息15-26,通过15-22获取模式值15-27,通过documentMode获取文档模式值15-28,由于标签15-11中没有设定documentMode属性故15-28为空,根据includeAnyMode获取使用默认模式15-29,没设置的话其默认为true。根据文档类型typeInfo15-26用getLayouts方法15-30获取其布局(即获取15-1文本类型中定义的布局),15-30中传入的第一个参数由文档模式值documentModeValue判断产生,若文档模式值为空传入模式值否则传入文档模式值,由于文档模式值15-28为空,传入模式值15-31,其值为15-32“edit”(同15-27),15-30中传入的第二个参数由使用默认模式useAnyMode判断产生,若使用默认模式15-29为true传入(BuiltinModes.Any)15-33,其值为15-34“any”,若文档类型中的布局(即15-1文本类型中的<layouts>标签)不为空,则从其布局15-35中提取模式(mode)为“edit”15-32的布局15-36(它对应着15-1中的15-3),若已提取布局15-36为空且默认模式(defaultMode)不为空,则从15-35中提取模式为默认模式“any”15-34的布局15-37,由于已提取布局15-36不为空,故跳过默认模式的判断,将已提取布局15-38(同15-36)中的layouts元素15-39通过方法15-30返回给15-40作为当前模式下将应用的布局,可以看到15-40中的3个布局分别对应了15-3中的3个布局,即编辑模式下的布局。依次提取15-40中的每个布局15-41“dublincore”,根据其布局名产生一个名字标签属性15-42,并加入模式属性15-22,值属性15-23组成dublincore布局的属性15-43,为其添加LeafFaceletHandler(即下一个处理器为空)和tagId(dublincore布局标签的标识符)组成标签信息15-44,将15-44添加到Facelet处理器15-45中,再将15-45添加到复合处理器15-46中,针对15-46执行apply方法,即应用复合处理器中的每一个布局(如dublincore布局)。
如图16所示,***将15图中提取到的当前可用布局以dublincore为例一一实现:
上图中***将标签信息16-1(同15-44)添加到Facelet处理器16-2(同15-45)中,具体步骤是用布局标签处理器LayoutTagHandler方法类下的同名方法16-3实例化dublincore标签信息16-4并将该LayoutTagHandler加入到Facelet处理器16-2中,方法16-3将提取标签信息16-4中的每条标签属性(即15-43),包括名字标签属性16-5(同15-42),其值为16-6,模式标签属性16-7(同15-22),值标签属性16-8(同15-23),布局标签处理器将利用这些属性来产生布局:name是在布局定义信息注册表reg中注册过的布局名;category是布局的类别;definition为布局定义信息,可以用它来动态地产生布局;layout用来具体定义一个布局实例;mode意味着将用什么模式下的布局渲染页面(具体效果见15-2至15-7);value意味着布局将使用的值,即暴露给前台xhtml的#{field}变量,具体的映射封装过程见(6-39至6-43);template意味着将为该布局使用的前台模板,如果设置的话将覆盖布局定义信息14-32中的template属性(14-35),其值为14-18,在XML文件中的14-3处定义;selectedRows是可选择的行名,如果不为空的话将用它过滤布局中的行;selectAllByDefault将指定是否默认选中(即显示)所有的行;resolveOnly意味着只在环境中处理和暴露将渲染的布局,而不将它立马显示。该dublincore布局由于是由文档布局标签处理器15-12批量产生的,只包含了名字、模式、值3个标签属性。15图的最后用复合处理器(composite)16-9(同15-46)来应用16-10每一个可用的布局,它将从复合处理器的孩子16-11(即添加到其中的Facelet处理器16-2中的布局标签处理器16-3列表)中依次提取每个布局标签处理器16-12,并对其使用布局标签处理器方法类中的apply方法16-13来应用每一个具体的布局标签:先用WebLayoutManager接口16-14定义一个布局服务,可以用它来管理已注册的布局定义信息及创建布局实例,然后从Framework中获取接口16-14的实现类(WebLayoutManagerImpl)16-15,根据布局定义处理器16-3中的标签属性来配置布局,例如selectedRows标签属性16-16不为空的话就用它来对布局中的行进行过滤,如果name标签属性16-17(同16-6)不为空,就提取其中的布局名16-18,并用布局服务16-19中的获取布局(getLayout)方法生成布局实例,即通过其实现类16-20中的getLayout方法产生具体的dublincore布局:它先用getLayoutDefinition方法16-21获取布局的定义信息:由于该布局没有设置类别标签属性,取默认的“jsf”类别16-22并用它来获取布局定义信息注册表(reg)16-23(同14-38),在16-23中查找布局名16-24(同16-18)为“dublincore”16-25的布局定义信息,即图14中在reg中注册的dublincore布局定义信息14-39,通过方法16-21将其返回到布局定义信息(layoutDef)16-26,从16-26中提取行定义信息16-27(同14-34),定义一个空的布局行列表16-28,设置一个值为-1的行指针16-29,依次提取16-27中的每个布局行定义信息16-30(同14-25),行指针16-31自增,即第一行的指针值为0,第二行的指针值为1,提取16-30的名字16-32,由于行14-5中没设置name属性故该name属性值为空,若行名字16-33为空,用“layout_row_”字符串加行指针值16-31组成新的行名子16-34,由于每行的行指针不同,行名子不会重复,可以在前台用行名字作为每行的id,设置布尔值(emptyRow)16-35以判断行是否为空,并默认其为true(空),若(selectedRows)16-36不为空的话用它对行进行过滤,提取行16-30的插件参考16-37(同14-28,在XML中由14-5定义),再提取插件参考16-37的名字16-38,在插件定义信息注册表中提取名为“subjects”16-38的插件定义信息16-39,并根据当前dublincore布局的参数用getWidget方法16-40获取一个符合当前运行环境的subjects插件实例(详情见图5),将该插件实例16-41加入插件列表widgets(因为一行中可能包含多个插件),若一行中有不为空的插件实例16-41,则将(emptyRow)16-42置为false,意味着该行不为空,若该行不为空用LayoutRowImpl方法16-43为该行产生一个布局行实例,将行名子16-44,是否默认选择该行16-45(同14-27),是否总是选择该行16-46(同14-26),刚产生的subjects插件实例16-47,行属性以及行的哈希值都***该布局行实例中,并在先前创建的空的布局行列表16-48中***这些布局行实例,用LayoutImpl方法16-49来实例化该dublincore布局,在其中***刚刚获取的布局行实例16-50,为其计算哈希值id信息16-51(该哈希值是由布局的各项属性参数计算产生的,故同一个布局对应同一个哈希值),再***名字、模式等参数该dublincore布局就实现了。这就是该***的布局实现方式,它在注册信息中定义一个只包含各插件名的简单布局,在显示布局时根据当前环境提取具体的插件实例,并将布局的各行填充完整。
如图17所示,***通过前台显示模板xhtml文件和后台布局架构xml文件来配置布局中的行:
修改“编辑”按钮对应的前台xhtml文件17-1,它将通过nxl:layout标签17-2用布局标签处理器LayoutTagHandler单独渲染dublincore布局17-3(即只渲染15-7),此时例子文本对应的编辑页面如17-4所示。17-5(同16-30)为将渲染的dublincore布局中的每个布局行定义信息,17-6(同16-36)为每行的判断过滤条件(图16中只是一笔带过此处详细说明),它将在选择行selectedRows是否为空的两种情况下根据布局的前台(17-1)后台(17-3)属性判断是否过滤掉该行:17-7将该行的总是选择alwaysSelected属性置为true,当***启动会默认将每行14-25中的alwaysSelected属性14-26置为false,17-7会将该行的14-26默认属性替换为true并将其保存到dublincore布局的注册定义信息中,此时由于17-8总是为true,无论selectedRows是否为空过滤条件都会被跳过。默认情况下selectedRows属性17-9为null(由于17-1中没设置selectedRows属性),selectAllRowsByDefault属性17-10为false(17-1中没设置的话默认为false),isAlwaysSelected属性17-8默认为false(同14-26),过滤条件均成立,由于默认选择selectedByDefault属性17-11默认为true(同14-27),过滤条件被跳过所以才能在前台页面中看到该行,17-12将含有subjects插件的行的selectedByDefault属性设置为false,使得17-13这最后一条过滤条件也成立,执行continue并跳过该行的加载程序,最后生成的布局实例17-14中行数17-15为4(相对布局实例16-49中行数16-50为5),其显示结果如17-16所示,可以看到它相对于17-4少了内容主题(subjects)一行。若在显示编辑页面的前台xhtml文件17-1中加入默认选中全部selectAllByDefault属性17-17,布局标签处理器17-2将提取该属性17-18(即在document_edit.xhtml中第3行第44列结束的nxl:layout标签中的selectAllByDefault=“true”属性),将其作为方法16-19的最后一个参数传入WebLayoutManagerImpl中的布局生成方法16-20,在过滤条件16-36中,由于17-19为true,selectedRows为空时过滤条件总是被跳过,因此编辑页面如17-4所示,显示所有行(包括默认不被选中的主题subjects行)。若在17-1中加入list变量17-20(一个存储’layout_row_1,source’的动态数组变量),并将list设置为selectedRows属性17-21的值,布局标签处理器17-2会从前台提取该属性17-22,由于其应用布局apply方法16-13中的selectedRows属性16-16此时不为空,具体运行该判断条件17-23,用selectedRowsValue变量17-24以字符串列表的形式提取selectedRows属性17-22中的#{list},将其作为16-19方法的倒数第二个参数传入生成布局方法,在过滤条件16-36中,由于此时selectedRows属性17-25不为空,每行的isAlwaysSelected属性默认为false,SelectedRows属性17-27中不包含的行将执行过滤条件continue并无法显示到前台,默认情况下布局行定义信息14-25中的name为null,生成布局时会根据行排序自动为无名的行命名,如subjects插件的行名为layout_row_1(具体步骤见16-31至16-34),也可在布局的xml文件17-3中为行17-26取名为source来代替默认的***生成名。本例中只有selectedRows属性17-27中包含的名为layout_row_1的行17-29和名为source的行17-30跳过了过滤条件,其显示结果如17-28所示。如上即是通过后台xml文件中的行属性和前台xhtml文件中的布局属性配置布局行的具体方法。
如图18所示,***用EL表达式计算主题sujects插件的插件模式,根据文档的主题元数据是否为空来决定是否显示主题插件:
18-1(同5-1)为XML文件中的主题subjects插件,它通过<widgetModes>标签18-2在插件定义信息中加入了模式modes属性,即在概览view_summary模式下判断文档的主题元数据layoutValue.dc.subjects是否为空empty,为空就设定该插件为隐藏hidden模式,不为空就设定该插件为浏览view模式。在***生成布局16-20时,会根据每行16-31中的插件名16-38用getWidget方法16-40获取该插件实例,即通过运行环境计算生成该subjects插件(详情见图5),在没设置插件模式的情况下会默认用当前布局的模式5-2作为该插件的模式5-3,在设置插件模式后会根据模式中的EL表达式具体计算该插件的模式。18-3为获取插件getWidget方法,它会用getModeFromLayoutMode方法18-4通过当前的概览布局模式18-5获取该插件的模式,18-4先用getMode方法18-6从插件模式集18-7(即18-2)中获取键值为概览(view_summary)的模式18-8,用getStringValue方法18-9计算18-8中的EL表达式来获得一个字符串形式的模式(如“hidden”,“view”):用其中的evaluateExpression方法18-10计算给定环境下的EL表达式:用其中的resolveElExpression方法18-11来找出并计算模式18-8中的所有EL表达式:它先用isValueReference方法18-12判断18-8中是否含有EL表达式,即看18-8中是否含有“#{”且其后有“}”18-13(或含有“#$”且其后有“}”),不含EL表达式就直接返回否则对EL表达式进行处理,获取该facelet环境下的表达式工厂(eFactory)18-14和与请求绑定的环境(elContext)18-15,通过18-14用createValueExpression方法18-16创建值表达式:它通过decorateELContext方法来包裹基本的EL环境18-15,为其添加功能映射18-18和变量映射18-19,最后生成的值表达式(expr)如18-20所示,可以看到它包括一个值为Object预期类型18-21,一个el表达式18-22(内容同18-8),一个为null的功能映射18-23(18-8中没引用任何功能标记),一个变量映射18-24,它是由metadata_dc_widget_template.xhtml(用以处理元数据插件的前台模板)传来的值为“#{currentDocument}”的变量,18-25为由18-8生成的节点,它是一个AstChoice选择节点,其孩子18-26中包含三个节点,分别为判断元数据是否为空的AstEmpty节点18-27及在元数据是否为空的情况下返回的“hidden”、“view”模式,18-27中又包含了AstValue值节点18-28,列出了从上到下依次要取的布局值layoutValue,都柏林架构的前缀dc,都柏林架构中的主题属性subjects,该subjects即为要用来判断是否为空的变量。对该值表达式(expr)18-20使用getValue方法18-29,它将调用值表达式实例ValueExpressionImpl方法类中的getValue方法18-30来获取值表达式18-20在当前环境中对应的值:它先用ElContext、功能映射、变量映射生成一个计算环境(ctx)18-31,再获取this(由值表达式18-20发起的获取方法18-30,this就是18-20)的节点18-32,即AstChoice选择节点,对其使用AstChoice方法类中的getValue方法18-33,它将取出18-32中第0个孩子18-34,即AstEmpty空节点,对该节点使用AstEmpty方法类中的getValue方法来判断文档的subjects属性是否为空:取出18-34中的第0个孩子18-35,即AstValue值节点,对该节点AstValue方法类中的getValue方法18-36来获取文档的subjects属性:获取18-35中的第0个孩子18-37,AstIdentifier节点,对它使用AstIdentifier方法类中的getValue方法18-38,它将先从环境计算18-31中取得变量映射18-39(即18-20的变量映射18-24),若其不为空取出this对象18-40(即AstIdentifier节点18-37)中的值18-41,并在18-39中取出键值为18-41(layoutValue)的内容作为新的值表达式18-42,对该值表达式使用值表达式实例ValueExpressionImpl方法类中的getValue方法18-43来获取它在当前环境下的值,在此时的getValue方法18-44(同18-43)中,由于没有传来的变量映射其计算环境18-45中的varMapper为null,取出this(即新的值表达式18-42)中的节点18-46,值为currentDocument的AstIdentifier节点,对其使用AstIdentifier方法类中的getValue方法18-47,由于此时环境18-45中的变量映射18-48为空,不再处理其下的变量映射,用getELResolver方法18-49获取EL处理器并直接将this(即18-46)中的值currentDocument取出返回到18-50,可以看到它取出了当前文档(即例子文本)的文档模型实例,将18-50返回到AstValue方法类的相对位置18-51并寻找该文档的subjects属性:取出this(即AstValue节点18-35)的孩子数(propCount)18-52并依此获取每个孩子的属性值,初始设置i=“1”18-53,取出该文档18-51的dc(18-35中的第1个孩子18-54)属性结果如18-55所示,它即为例子文本的dublincore数据架构,i自增到“2”18-56,取出都柏林数据架构18-55中的subjects(18-35中的第2个孩子18-57)属性结果如18-58所示,可以看到它包含了cinema(电影)、comics(漫画)两个孩子,将18-58返回到AstEmpty方法类的相对位置18-59用以判断该值是否为空,由于18-59不为空返回“FALSE”18-60到AstChoice方法类的相对位置18-61,由于三目运算符的条件18-61为false,返回其第二个值“view”18-62到ValueExpressionImpl方法类的相对位置18-63作为方法18-29在当前环境下对值表达式18-20的计算结果,将其返回到方法18-10的相对位置18-64以检查其中是否还含有EL表达式,通过resolveExpression方法18-65来处理18-64,由于传来的表达式18-66不包含el表达式的符号(18-12返回false)直接返回该表达式,最后将“view”返回到18-67作为该插件的模式,它将调用subjects插件的插件类型“suggestManyDirectory”4-1中的view布局4-19来显示插件,因此可以在概览页面看到该主题subjeets插件18-68。若例子文本中没为主题subjects插件设置元数据,在AstValue方法类中取出的subjects属性值为空18-69,返回到AstEmpty方法类的对应位置18-70,由于18-70为空返回“TRUE”18-71到AstChoice方法类的对应位置18-72,由于三目运算符的条件18-72值为true,返回其第1个值“hidden”18-73,最后将“hidden”返回到18-74做为插件的模式wMode,可以从5-4看到当插件模式wMode等于“hidden”时将直接返回null,不再运行接下来的插件加载程序,故此时的概览页面中看不到主题subjects插件18-75。如上就是通过插件模式控制插件的具体方法。
如图19所示,***通过插件模式中的标记功能nxd:hasPermission规定只有对当前文档有写权限的用户才能看到和编辑该文档:
将subjects的插件模式设置成19-1所示,它意味着调用nxd标签下的hasPermission方法判断用户是否对当前文档(currentDocument)有写(Write)权限,有的话就将插件设置成编辑‘edit’模式,否则将插件设置成隐藏‘hidden’模式。对“例子文本”设置权限如19-2所示,给Writer用户“写入”的权限,给Reader用户“读”的权限。此时用Writer用户点击“例子文本”的概览选项卡,插件获取模式的步骤起初与图18(18-3至18-15)一样,当运行到resolveElExpression方法19-3(同18-11)中的createValueExpression创建值表达式方法19-4(同18-16)时,它将通过方法18-17包裹EL环境,为其添加功能映射,因此任何带有nxd:hasPermission的表达式必须通过Facelets(因为他们被定义在标签库中)进行计算,***将在<facelet-taglib>标签中寻找命名空间http://nxweb/document19-6(其前缀为nxd)中名为hasPermission的方法19-9,它将映射到ecm.platform.ui.web.tag.fn包19-7中的DocumentModelFunctions方法类19-8中的hasPermission方法19-9,其接口参数为19-10,包含一个文档模型和字符串格式的变量。19-4创建的值表达式expr如19-11所示,它包括预期的Object类型19-12,El表达式19-13(同19-1),其中的AstChoice选择节点19-14包含了AstFunction功能节点19-15(用以通过hasPermission方法检查权限)及用于选择的两个AstString字符串节点‘edit’和‘hidden’,其功能节点19-16又包含了AstIdentifier标志节点19-17用于获取特定文档及AstString节点19-18用以指出需要判断的权限,19-17和19-18即为hasPermission方法的两个参数。19-11中的功能映射“fnMapper”19-19中的功能哈希表“functions”19-20包含了所有映射过来的功能,比如这个键值为“nxd:hasPermission”19-21的功能映射实例19-22,它的前缀为“nxd”19-23,本地名为“hasPermission”19-24,它的方法19-25为一个返回布尔值的公共方法,为ecm.platform.ui.web.tag.fn包19-7中DocumentModelFunctions方法类19-8中的hasPermission方法19-9,包含的参数如19-10所示。19-26为19-11的变量映射,由于19-1中没调用任何变量故其值为null。对19-11执行值表达式实例ValueExpressionImpl方法类中的getValue方法19-27,它根据el环境及19-11中的功能变量映射组成计算环境(ctx)19-28,可以看到其功能映射不为空而变量映射为空(与18-31正好相反),取this(即19-11)的节点19-29(AstChoice选择节点),并根据它发起AstChoice方法类19-30中的getValue方法19-31,用以选择插件模式,取this(即AstChoice节点19-29)中的第0个孩子19-32(即AstFunction节点)并根据它发起AstFunction方法类19-33中的getValue方法19-34用以执行hasPermission方法判断用户是否对当前文档有写权限,它从环境(ctx)19-28中获取功能映射(fnMapper)19-35,并根据该功能映射发起功能映射实例FunctionMapperImpl方法类19-36中的resolveFunction方法19-37以获取具体的hasPermission方法,并将this对象19-38(同19-16中的AstFunction功能节点)中的‘prefix’19-39和‘localName’19-40作为参数传入方法19-37。方法19-37在this对象19-41(即发起它的功能映射‘fnMapper’19-35)中的功能映射表(functions)19-42中寻找键值为“19-39+‘:’+19-40”(即‘nxd:hasPermission’19-21)的功能映射实例19-43,并返回19-43中的方法(Method)19-44。根据this对象19-16的孩子数创建一个内容为空的参数对象(params)19-45,依次将19-16中的每个孩子19-46的计算值塞入19-45,如根据19-17用AstIdentifier方法类中的getValue方法取出当前文档currentDocument的文档模型实例(具体步骤见18-47至18-50),再根据19-18用AstString方法类中的getValue方法取出‘Write’的字符串形式‘Write’,生成的新参数对象如19-47所示,最后用调用方法‘invokeMethod’19-48以19-44和19-47为参数发起hasPermission方法19-49,方法19-49会获取一个文档管理“documentManager”会话,执行该会话方法类中的hasPermission方法19-51,19-51会通过安全服务发起检查权限checkPermission方法19-52,在方法19-52中***会获取文档19-53(即当前文档‘例子文本’)中的访问控制策略‘acp’19-54,19-54中的访问控制列表‘acl’中具体列出了管理员为该文档设置的局部权限,它包括了用户(Writer)19-55的写入ReadWrite权限19-56(ReadWrite代表读和写),以及用户(Reader)19-57的读(Read)权限19-58,通过安全策略服务发起checkPermission方法19-59检查在访问控制策略‘acp’19-60(同19-54)中用户(Writer)19-61是否含有写(Write)19-62权限,可以通过19-55和19-56看到用户Writer对该文档有写权限,将该检查结果以Boolean的形式返回到19-63,进一步返回到AstChoice选择节点的相对位置19-64,由于三目运算符的条件19-65为true,将选择返回第1个选项‘edit’19-66到getWidget方法19-67(同18-3)中的‘wMode’19-68(同18-67)作为插件模式。如果是用户Reader点击‘例子文本’的概览选项卡,将在访问控制策略‘acp’19-60(同19-54)中检查用户(Reader)19-69是否有写(Write)19-62权限,可以在19-54中看到用户Reader没有写权限,检查失败19-63返回false到AstChoice选择节点的相对位置19-64,并选择三目运算符的第2个选项‘hidden’,最后的插件模式(wMode)19-70为隐藏‘hidden’。如上就是通过插件模式中的标记功能控制插件的具体方法。
如图20所示,***中有创建用户、编辑用户、查看用户、修改用户密码等多个有关用户的页面,但其实他们都衍生自同一个用户布局,只是根据布局模式的不同而屏蔽掉部分插件使用户布局显示成不同的样子:
20-1是名为用户(user)的布局,它由用户名、密码等13个插件行20-2组成,由于各个插件的插件模式的影响,布局在不同的模式下会呈现出截然不同的样子。20-1中大部分插件的插件模式<widgetModes>都如邮件“email”20-3一样,在编辑密码“editPassword”20-4等特殊的状态下为隐藏“hidden”20-5模式,在其余通常状态(如浏览、编辑)下呈现和布局相同的模式,比如用户名插件20-6、姓名插件20-7、所在单位插件20-8都和邮件插件20-9一样在布局的浏览模式下呈现该插件的浏览状态20-10;在布局的“编辑”20-11模式下呈现该插件的编辑状态20-12,其中邮件插件20-3的属性(properties)20-13中声明在“编辑”20-14模式下该插件为必选的“required”20-15且其样式“styleClass”20-16为数据输入文本样式dataInputText;在布局的“改变密码”20-17模式下呈现该插件的隐藏状态20-18,可以看到当布局为改变密码模式时绝大部分插件都不见了,此时只能看到在该特定模式下专用的几个插件如密码(第一次输入密码)20-19和原始密码20-20,20-19中规定了除了在创建“create”20-21、改变密码“editPassword”20-22模式下该插件呈编辑“edit”状态,在其余任何“any”20-23模式下该插件均呈隐藏“hidden”状态,20-20中规定了除了在改变密码“editPassword”20-24模式且当前主选项卡“isOnMainTab”20-25为我的主页‘home’20-26时该插件为编辑“edit”20-27状态,在其余任何“any”20-28状态下该插件均隐藏。接下来就通过“邮件”的插件模式20-29和“原始密码”的插件模式20-30来具体说明插件模式是如何在布局的不同模式下判断生效的。在获取插件getWidget20-31方法的通过布局模式获取模式getModeFromLayoutMode方法20-32中,非el表达式的插件模式都是通过getMode方法20-33直接获取的,当布局模式为浏览“view”20-34时,加载邮件插件时会从其插件模式20-35中查找键值为布局模式“view”20-36的内容,由于20-35中没有键值为“view”的键值对,其查找结果为空(null)20-37,当查找结果为空时***会尝试查找键值为任何“any”20-38的内容,由于20-35中也没有键值为“any”的键值对,其查询结果为空(null)20-39,将该结果返回到插件模式20-40,当插件模式为空时会用getWidgetModeFromLayoutMode方法20-41获取当前布局的模式作为该插件的模式,可以在20-41中看到,当布局模式起始于浏览“VIEW”、概览“SUMMARY”、列表“LISTING”、标题“HEADER”时将返回浏览“VIEW”20-42作为该插件的模式20-43,故可以在布局的浏览模式20-10中看到邮件20-9的浏览状态,这就是为什么插件在通常状态(如浏览、编辑)下呈现和布局相同的模式;当布局模式为浏览“view”20-34时,加载原始密码插件时会从其插件模式20-44中查找键值为“view”20-36的内容,由于20-44中没有键值为“view”的键值对查找结果20-37为空,***默认从20-44中查找键值为“any”20-38的内容20-45,将其结果“hidden”返回到插件模式20-47中,故在布局的浏览模式20-10下看不到原始密码,该插件在“editPassword”模式以外的任何“any”20-45模式下均呈隐藏状态;当布局模式为改变密码“editPassWord”20-48时,加载邮件插件时会从其插件模式20-35中查找键值为“editPassword”20-49的内容,由于20-35中键值“editPassword”对应的内容为“hidden”,将查找结果20-46返回到插件模式20-47,故在布局的改变密码“editPassWord”模式“20-18”下看不到邮件插件,这也是为什么在布局的“editPassword”模式下大部分插件呈隐藏状态;当布局模式为改变密码“editPassword”时,加载原始密码插件时会从其插件模式20-44中查找键值为“editPassword”20-49的内容,可以在20-44中看到键值“editPassword”对应的内容为一个el表达式,由于查询结果20-50通过了方法18-13的el表达式格式验证,将在返回插件模式前将其用方法19-3计算这个el表达式,通过nxu命名空间中的test方法判断‘主选项卡mainTabActions’方法类中的‘当前主选项卡isOnMainTab’是否为‘我的主页home’,并根据判断结果选择“edit”或“hidden”模式,这样一来当管理员想在“我的主页”20-26中修改自己的密码时需要先输入原始密码20-20以保证安全,当管理员想在“***管理”20-52中为别人(如用户BBB)“改变密码”20-53时不需输入原始密码从而使操作方便。如上就是布局的重用原理,正是通过对插件模式的多样化判断使得同一张用户布局在不同的模式下呈现出了有着不同外貌及功能的千姿百态的用户信息页面。
如图21所示,***展示了如何通过nxu:test这个标记功能测试***任意方法类中的方法或由多个条件组成的逻辑表达式,并根据结果逻辑值为插件选择对应的模式:
用方法21-1来计算插件模式20-30中的el表达式,它首先创建值表达式“expr”21-2,可以从21-2中看到其具体的el表达式21-3,其节点为一个AstFunction功能节点21-4,包括一个用于判断的AstValue值节点21-5和两个用于选择的AstString节点作为备选的插件模式,值节点21-5中包括了一个AstIdentifier标记节点21-6用于寻找具体的方法类mainTabsActions,以及一个AstMethodSuffix方法节点21-7用于调用isOnMainTab方法(图19中的标记功能nxd:hasPermission用以判断当前文档的权限,其参数为当前文档、写权限等变量;而本图中的标记功能nxu:test用以判断方法isOnMainTab的计算结果,其参数为方法类和方法)。21-2中含有一个功能映射21-8,它是在<facelet-taglib>标签21-9中定义的命名空间为“http://nxweb/util”21-10(缩写为nxu)方法名为“test”21-11的标记功能,它引用的是ecm.platform.ui.web.tag.fn包21-12中Functions方法类21-13中的test方法,nxu:test的参数类型如21-14所示,包含一个Boolean作为方法调用的结果,包含两个Object作为待选的插件模式。用值表达式实例ValueExpressionImpl方法类21-15中的getValue方法21-16来获取21-2中计算的插件类型:它先取出21-2的AstFunction功能节点21-17,运行AstFunction方法类21-18中的getValue方法21-19来获取标记功能nxu:test的计算结果:从计算环境中取出21-2的功能映射21-20,根据功能节点21-17中的前缀(prefix)21-21和本地名(localname)21-22从功能映射21-20中获取具体的方法21-57(具体步骤见19-39至19-44),根据功能节点21-17中的孩子数创建一个空的参数数组(params)21-23,,将21-17中的孩子节点的值依次塞入21-23,先取21-17的第0个孩子21-24(即AstValue节点21-5),用AstValue方法类中的getValue方法21-25计算其值:它将先取出AstValue值节点21-5的第0个孩子21-26,根据这个内容为mainTabsActions的AstIdentifier标志节点取出MainTabsActions方法类21-27,i自增‘1’21-28并继续取21-5的第1个孩子,内容为isOnMainTab的AstMethodSuffix方法节点21-29,通过AstMethodSuffix方法类中21-30中的getValue方法取出该方法的计算结果:首先通过getParameters方法21-31取出参数,根据AstMethodSuffix方法节点21-29的孩子数创建一个空的对象数组21-32,将该AstMethodSuffix节点21-33的所有孩子(比如内容为home的AstString节点21-34)的值塞入21-32,最后将填充好的对象数组21-35返回21-31作为参数,用invokeMethod方法21-36调用这个以“MainTabsActions”21-37为方法类,以21-29的镜像值(isOnMainTab)21-38为方法名,以(home)21-35为参数的isOnMainTab方法21-39:该方法将判断当前主选项卡是否为21-40(home),它先从WebActions方法类中取出主要选项卡类别(MAIN_TABS_CATEGORY)21-41的值“MAIN_TABS”(该值为一个常数变量),再用getCurrentTabId方法21-42取出当前类别为“MAIN_TABS”21-43的选项卡的Id,它需要先通过getCurrentTabAction方法21-44取出具体的当前选项卡操作项,在当前选项卡操作项集合(currentTabActions)21-45中可以看到:当前的主要选项卡MAIN_TABS(也可以说是页眉选项卡)21-46中选中的是我的主页(home)选项卡21-47,当前的用户侧边栏(USER_CENTER)21-48中选中的是我的名片信息(Profile)选项卡21-49,从21-45中取出键值为“MAIN_TABS”21-50的选项卡操作项21-51,并取其Id(home)21-52,用当前主选项卡的(Id)21-52和传来的参数21-53进行比较,若想等的话将true返回到21-54作为AstValue值节点的计算结果,该结果“true”将通过21-24被塞入到AstFunetion节点的参数数组21-55中,然后再陆续将节点21-17的另外两个孩子(内容为edit和hidden的两个AstString节点)塞入21-55,通过invokeMethod方法21-56发起这个以21-57为方法以21-58为参数的test方法21-59,它将以其第一个参数21-60(同21-55中的第一个孩子)作为三目运算符的条件选择返回“edit”21-61或“hidden”21-62,由于21-60为true将test方法21-59的第二个参数“edit”返回到值表达式方法类21-15中的对应位置21-63,该“edit”即为值表达式21-2的计算结果也就是该插件将使用的模式,因此在改变密码模式20-17下,当主要选项卡为我的主页20-30时能编辑原始密码20-20。当主要选项卡为***管理时,此时getCurrentTabAction方法21-44获取的选项卡操作项如21-64所示,其Id为“admin”21-65,与21-53不相等故返回“false”21-66,此时参与test方法的参数数组如21-67所示(其第一个孩子为false),由于test方法21-59的三目运算符条件为“false”21-68,将返回其第3个孩子“hidden”作为插件的模式21-69,因此在改变密码20-53模式下,当主要选项卡为***管理20-52时看不到原始密码。如上就是nxu:test的使用方法,它可以将任何返回值为Boolean的方法作为参数,并根据其判断结果选择对应的插件模式,这样一来就能以nux:test标记功能作为接口,让***中任意返回值为Boolean的方法参与插件模式的计算工作。nxu:test不光能以方法为参数,它还能以逻辑表达式作为参数,如21-70所示,nxu:test以“当前用户currentUser是管理员administrator或当前用户currentUser是超级用户组‘powerusers’的成员”这个逻辑表达式为三目运算符的条件选择返回“edit”或“view”模式:通过AstOr方法类21-71中的getValue方法取出该或逻辑表达式的逻辑结果:首先对AstOr或节点21-72的第0个孩子21-73(即currentUser.administrator)使用AstValue方法类21-74中的getValue方法21-75判断其是否为true:先取出当前AstValue值节点的第0个孩子21-76,根据这个值为“currentUser”的AstIdentifier标志节点获取当前用户的信息21-77(假设当前用户是BBB),再取出当前AstValue值节点的下一个孩子21-78,根据这个值为administrator的AstPropertySuffix节点取出当用用户信息21-77中的isAdministrator属性21-79,将其结果“false”返回到AstOr节点的对应位置21-80作为逻辑或中第一个表达式的计算结果,若21-81(同21-80)为true将直接返回true,由于此时21-81为false继续判断逻辑或中的下一个表达式,取出AstOr或节点21-72中的第一个孩子21-82(即currentUser.isMemberOf(’powerusers’)),用AstValue方法类的getValue方法计算该表达式的值:先取出该AstValue节点的第0个孩子“currentUser”21-83的值21-77,再取出该节点的第1个孩子21-84,根据该值为isMemberOf的AstMethodSuffix方法节点发起isMemberOf方法21-85,判断当前用户信息21-77的所有组(allGroups)21-86中是否包含超级用户组(powerusers)21-87,可以看到21-86中包含了成员组“members”和B区成员组“tenant-B区_tenantMembers”但不包含powerusers,故AstOr节点或逻辑的第二个表达式的值也为“false”21-88,将21-88返回到21-70作为三目运算符的条件,由于其为false选择第3个参数“view”21-89,即用户BBB能浏览该插件;当用户为总管理员Administrator时,由于其用户信息中的isAdministrator属性21-90为true,AstOr节点中逻辑或的第一个表达式值为“true”21-91,将“true”返回到21-70作为三目运算符的条件,此时将选择第2个参数“edit”21-92,故总管理员Administrator能编辑该插件。如上所示,可以通过nxu:test来判断由不同变量/方法条件组成的逻辑表达式,这大大增强了插件模式的灵活多样性。
如图22所述,通过插件模式的设置使同一个插件对不同用户显示不同的效果,或在布局的特定位置设置几个功能相似的插件,通过插件模式的过滤使得用户只能看到符合自己权限的插件版本,从而达到插件的重用:
22-1(同20-1)为用户布局,22-2为布局中的用户所属群组插件,其插件模式在编辑22-3模式下用nxu:test标记功能22-4声名了只有***管理员或超级用户才能编辑该插件,其他人只能来浏览该插件(具体步骤见21-70至21-92),因此***管理员Administrator22-5在修改个人信息时能看到用户所属群组的编辑状态22-6,可以通过点击叉子来让自己退出某个群组,也可以通过输入3个字符来搜索并进入某个群组;而普通用户(BBB)22-7只能看到用户所属群组的浏览模式22-8,无法对自己的群组进行任何操作。如上就是插件重用的具体方法,同样一个插件通过插件模式的设置可以让不同的用户看到不同的效果。22-9为区域选择插件,它通过nxu:test标记功能22-10使得在创建22-11和编辑(编辑的插件模式同创建一样,由于地方不够图中省略了)模式下只有***管理员能编辑该插件,其他用户无法看到该插件,它通过webActions方法类的checkFilter方法22-12来检查当前用户是否通得过过滤器only_for_manager的校验:它先用过滤器注册表(filterReg)22-13取出***中的所有过滤器,再在22-13中取出键值为22-14(即向该方法传入的参数only_for_manager字符串22-15)的过滤器(filter)22-16,该过滤器是在22-17中定义的,其id为only_for_manager,它规定当#{userSession.administrator}(即当前用户为***管理员)条件22-18成立时授予(grant)22-19检查通过(true),此时插件模式为编辑22-20,其他用户(通不过only_for_manager过滤器检查的非***管理员用户)无法看到22-21该插件。插件通过一个<selectOptions>标签22-22保存下拉列表中的选项,它通过multiTenant方法类中的getTenants方法22-23获取***中所有的区域:它先获取目录服务22-24,通过目录服务打开一个通向数据库中“tenants”22-25表的会话,并通过该会话取出tenants表中的所有词条22-26(从会话中取词条的详细步骤见8-8至8-23,getEntries()方法相当于发起一个过滤器为空的查询操作,即没有过滤条件获取表中的所有词条),通过一个显示标签为“None”22-27的空选项和用22-26中每个词条的label属性22-28作为显示标签的多个区域选项组成该插件的下拉列表选项,其显示效果如22-29所示,该插件意味着***管理员在创建(或编辑)用户时可以将他分配到任意区域。22-30为另一个区域选择插件,它和22-9有着一样的插件类型、显示标签和前台样式,只是有如下一些微小的差别:其name比22-9的name后面多了一个1(一个布局下不能有两个相同名字的插件);它在创建模式下用nxu:test标记功能22-31声明只有区域管理员能编辑该插件,其他人无法看到该插件,其用于检验的过滤器tenantPowerusers是在22-32中定义的,它规定当条件#{currentUser.isMemberOf(’powerusers’)}22-33(即当前用户是超级用户/区域管理员)成立时授予检查通过“true”,此时插件为“edit”状态,当条件#{currentUser.administrator}22-34(即当前用户是***管理员)成立时授予检查不通过“false”,此时插件状态为hidden,这样一来只有***管理员以外的超级用户(即区域管理员)可以编辑该插件。该插件的<selectOptions>标签22-35中保存了其下拉列表中的选项,它先用userPreferencesActions方法类中的getUserProfile方法22-36获取当前用户的资料(currentUserProfile)22-37,再从22-37中找出user架构22-38中的tenantId属性22-39并用该属性值作为选项的显示标签,其显示效果如22-40所示,这意味着当区域管理员创建用户时他只能创建属于该区域的用户,22-41定义了在编辑模式下隐藏该插件,这是由于该插件是区域管理员专用的,其区域下拉列表中也总共只有一个选项,因此编辑用户的区域(只能从B区再改成B区)也是无意义的。如上就是插件的另一种重用方法,在一张布局中的同一位置连续设置几个外貌相同功能相似的插件,通过插件模式进行选择性地过滤,使得不同用户调用该插件时都会看到该插件符合当前用户权限的那个版本,如***管理员22-42看到的区域选择插件能选择所有区域,而区域管理员22-43看到的区域选择插件只能选择该管理员所在的区域。
Claims (10)
1.一种XML配置网站方法,将XML中的内容映射到网站,其特征是:在XML文件中通过扩展标签<extension>来定义部件,扩展标签包含一个扩展目标属性用于指明在页面中加载该类部件的方法类,以及一个扩展点属性用于指明解析该部件XML内容的解析器,用户可以在扩展标签中对部件进行配置(如设置插件的显示内容)或组装(如在布局中***插件),***启动时会通过扩展点获取解析该部件的解析器并将该部件的XML内容映射成一个java对象,页面调用时会通过扩展目标计算该java对象(根据运行环境判断是否显示该部件以及根据部件属性生成前台样式)生成网页组件,从而使得用户可以通过XML方便地配置网站。
2.根据权利要求1所述的XML配置网站方法,一种建立目录方法,其特征是:根据directories扩展点配置目录,据其数据源属性设置数据库连接方式,据其架构属性设置各栏目名及其类型,据其数据文件属性载入各词条信息,据其建表策略属性设置目录的数据更新方式。
3.根据权利要求1所述的XML配置网站方法,一种配置插件方法,其特征是:根据widgettypes扩展点配置插件类型,根据widgets扩展点配置插件,将插件绑定插件类型,插件将继承插件类型中的前台模板、后台处理方法、布局及属性。
4.根据权利要求3所述的插件配置方法,一种插件显示方法,其特征是:将插件中保存的数据组装成标签的形式显示到前台,将插件在XML文件中定义的属性作为后台处理程序的判断条件或封装成标签属性暴露到前台模板,从而通过修改XML深入地影响插件的表现及功能。
5.根据权利要求2所述的建立目录方法,一种显示目录方法,其特征是:获取目录的所有词条并通过迭代的方式将它们生成一个JSONAdapter树,再通过javascript将其生成一个下拉列表中可用的词汇树,根据每个词汇的属性为其添加对应的css样式。
6.根据权利要求1所述的XML配置网站方法,一种XML提取方法,其特征是:***提取插件的XML信息并将其生成一个只包含扩展目标,扩展点及原XML文件地址的注册信息,当扩展目标未加载时将该注册信息放入等待该扩展目标的队列,当扩展目标加载后从中找出注册信息中的扩展点所对应的描述符,通过该描述符从注册信息中的原XML文件地址中取出该插件具体的配置信息,并将其注册成与扩展点同类型的java对象。
7.根据权利要求1所述的XML配置网站方法,一种布局调用方法,其特征是:每种类型的文档都包含了用以在不同模式下显示的布局集,每个布局集都由一个或多个布局组成,可通过针对布局集或布局的facelet处理器加载这些布局。
8.根据权利要求1所述的XML配置网站方法,一种布局建立方法,其特征是:根据layout扩展点配置布局,布局中的每行只包含了插件的名字,在调用布局时根据每个插件的名字取出插件定义信息,再根据运行环境计算出具体的插件实例,用插件实例将布局的各行填充完整,可通过布局的XML配置信息定义该布局中总是、默认及从不选中的行,可在任何调用该布局的前台facelet标签中选择显示该布局中的某几行。
9.根据权利要求1所述的XML配置网站方法,一种插件模式计算方法,其特征是:在每个插件的XML信息中都有一个<widgetModes>标签用以保存该插件在不同布局模式下的插件模式计算方法,这些计算方法可以直接返回一种特定的模式,也可以根据***变量判断选择某种模式,还可以根据标记功能的计算结果判断选择某种模式,通过nxu:test标记功能可以让***中任何返回布尔值的方法作为选择模式的判断条件,若<widgetModes>内容为空插件将继承其所属布局的模式。
10.根据权利要求9所述的插件模式计算方法,一种布局重用方法,其特征是:通过插件模式的多样化判断使得同一张布局在不同模式下呈现出不同的表现及功能,通过在插件模式中加入对当前用户的权限检查使得同一个插件可以让不同用户看到不同效果,可以在布局中的同一位置连续设置几个外貌相同功能相似的插件,通过插件模式的选择性过滤使得不同权限的用户都只能看到那个符合自己权限的插件版本。
Priority Applications (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN201510312172.7A CN105095348B (zh) | 2015-06-09 | 2015-06-09 | 一种通过xml动态配置网站的方法 |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN201510312172.7A CN105095348B (zh) | 2015-06-09 | 2015-06-09 | 一种通过xml动态配置网站的方法 |
Publications (2)
Publication Number | Publication Date |
---|---|
CN105095348A true CN105095348A (zh) | 2015-11-25 |
CN105095348B CN105095348B (zh) | 2019-03-26 |
Family
ID=54575785
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN201510312172.7A Active CN105095348B (zh) | 2015-06-09 | 2015-06-09 | 一种通过xml动态配置网站的方法 |
Country Status (1)
Country | Link |
---|---|
CN (1) | CN105095348B (zh) |
Cited By (25)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN104978196A (zh) * | 2015-06-26 | 2015-10-14 | 深圳Tcl数字技术有限公司 | 显示设置功能项的方法及装置 |
CN105700925A (zh) * | 2016-01-13 | 2016-06-22 | 深圳市华讯方舟软件信息科技有限公司 | 一种app的界面实现方法和装置 |
CN107273138A (zh) * | 2017-07-04 | 2017-10-20 | 杭州铜板街互联网金融信息服务有限公司 | 基于Android业务模块间交互的解耦方法和*** |
CN107329745A (zh) * | 2017-06-16 | 2017-11-07 | 贵州广思信息网络有限公司 | 一种增强word文档可操作性的方法 |
CN108287713A (zh) * | 2017-12-22 | 2018-07-17 | 深圳康得新智能显示科技有限公司 | 文档功能的添加方法及装置、终端、存储介质、电子装置 |
CN109445890A (zh) * | 2018-10-09 | 2019-03-08 | 北京达佳互联信息技术有限公司 | 一种界面展示方法、装置、终端设备及存储介质 |
CN109614085A (zh) * | 2018-10-23 | 2019-04-12 | 深圳微迅信息科技有限公司 | 功能实现方法、装置、计算机设备及存储介质 |
CN109977670A (zh) * | 2019-03-12 | 2019-07-05 | 福建天晴数码有限公司 | 基于插件加载的安卓应用安全监测方法、存储介质 |
CN110232173A (zh) * | 2018-03-06 | 2019-09-13 | 福建天泉教育科技有限公司 | 基于可配置化表单引擎的表单配置方法及其*** |
CN110263279A (zh) * | 2019-05-08 | 2019-09-20 | 北京字节跳动网络技术有限公司 | 页面生成方法、装置、电子设备和计算机可读存储介质 |
CN110442419A (zh) * | 2019-08-15 | 2019-11-12 | 北京字节跳动网络技术有限公司 | Android应用的界面布局方法及装置 |
CN110750248A (zh) * | 2018-07-23 | 2020-02-04 | 贵州白山云科技股份有限公司 | 一种用于传递现有组件的扩展信息的方法及装置 |
CN111459570A (zh) * | 2020-03-30 | 2020-07-28 | 掌阅科技股份有限公司 | Pdf插件加载方法、电子设备和计算机存储介质 |
CN111813385A (zh) * | 2020-07-07 | 2020-10-23 | 赞同科技股份有限公司 | 一种基于Web应用的页面插件化方法、装置及设备 |
CN111897469A (zh) * | 2020-07-06 | 2020-11-06 | 上海泛微网络科技股份有限公司 | 一种实时数据处理方法、装置、设备和存储介质 |
CN112632920A (zh) * | 2020-11-16 | 2021-04-09 | 腾讯科技(深圳)有限公司 | 一种链接处理方法、链接处理装置、终端设备及存储介质 |
CN113065314A (zh) * | 2021-03-26 | 2021-07-02 | 山东英信计算机技术有限公司 | 一种基于xml文件格式的bios硬件适配方法及装置 |
CN113076462A (zh) * | 2021-03-25 | 2021-07-06 | 恒安嘉新(北京)科技股份公司 | 网络会话数据查询方法、装置、设备及介质 |
CN113342417A (zh) * | 2021-06-15 | 2021-09-03 | 京东数科海益信息科技有限公司 | 插件配置方法、装置和设备 |
CN114064662A (zh) * | 2022-01-13 | 2022-02-18 | 北京中交兴路信息科技有限公司 | 查询数据的方法、装置、电子设备及介质 |
CN114090523A (zh) * | 2022-01-19 | 2022-02-25 | 荣耀终端有限公司 | 电子设备及其xml文件的节点解析方法、介质 |
CN114595199A (zh) * | 2022-05-10 | 2022-06-07 | 太平金融科技服务(上海)有限公司 | 文件解析方法、装置、计算机设备和存储介质 |
US20230130527A1 (en) * | 2021-01-04 | 2023-04-27 | Capital One Services, Llc | Dynamic review of software updates after pull requests |
CN116301831A (zh) * | 2023-03-20 | 2023-06-23 | 中国华能集团有限公司北京招标分公司 | 一种dp插件及其使用方法 |
CN116302076A (zh) * | 2023-05-18 | 2023-06-23 | 云账户技术(天津)有限公司 | 一种基于解析配置项表结构进行配置项配置的方法及装置 |
Citations (2)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN1993694A (zh) * | 2004-07-30 | 2007-07-04 | 西门子公司 | 基于模板的网页动态生成方法、程序和*** |
CN102646102A (zh) * | 2011-02-22 | 2012-08-22 | 青岛海信电器股份有限公司 | Xml文件生成方法及装置、终端设备 |
-
2015
- 2015-06-09 CN CN201510312172.7A patent/CN105095348B/zh active Active
Patent Citations (2)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN1993694A (zh) * | 2004-07-30 | 2007-07-04 | 西门子公司 | 基于模板的网页动态生成方法、程序和*** |
CN102646102A (zh) * | 2011-02-22 | 2012-08-22 | 青岛海信电器股份有限公司 | Xml文件生成方法及装置、终端设备 |
Non-Patent Citations (3)
Title |
---|
刘升平 等: "一种XML的模型论语义", 《软件学报》 * |
刘淑梅: "XML技术在动态网站中的应用", 《邢台职业技术学院学报》 * |
王雅光 等: "基于XML实时动态模型界面的研究与应用", 《计算机应用与软件》 * |
Cited By (35)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN104978196A (zh) * | 2015-06-26 | 2015-10-14 | 深圳Tcl数字技术有限公司 | 显示设置功能项的方法及装置 |
CN105700925A (zh) * | 2016-01-13 | 2016-06-22 | 深圳市华讯方舟软件信息科技有限公司 | 一种app的界面实现方法和装置 |
CN105700925B (zh) * | 2016-01-13 | 2019-02-19 | 深圳市华讯方舟软件信息有限公司 | 一种app的界面实现方法和装置 |
CN107329745A (zh) * | 2017-06-16 | 2017-11-07 | 贵州广思信息网络有限公司 | 一种增强word文档可操作性的方法 |
CN107273138A (zh) * | 2017-07-04 | 2017-10-20 | 杭州铜板街互联网金融信息服务有限公司 | 基于Android业务模块间交互的解耦方法和*** |
CN108287713A (zh) * | 2017-12-22 | 2018-07-17 | 深圳康得新智能显示科技有限公司 | 文档功能的添加方法及装置、终端、存储介质、电子装置 |
CN110232173A (zh) * | 2018-03-06 | 2019-09-13 | 福建天泉教育科技有限公司 | 基于可配置化表单引擎的表单配置方法及其*** |
CN110750248A (zh) * | 2018-07-23 | 2020-02-04 | 贵州白山云科技股份有限公司 | 一种用于传递现有组件的扩展信息的方法及装置 |
CN109445890A (zh) * | 2018-10-09 | 2019-03-08 | 北京达佳互联信息技术有限公司 | 一种界面展示方法、装置、终端设备及存储介质 |
CN109614085A (zh) * | 2018-10-23 | 2019-04-12 | 深圳微迅信息科技有限公司 | 功能实现方法、装置、计算机设备及存储介质 |
CN109977670A (zh) * | 2019-03-12 | 2019-07-05 | 福建天晴数码有限公司 | 基于插件加载的安卓应用安全监测方法、存储介质 |
CN110263279B (zh) * | 2019-05-08 | 2021-08-10 | 北京字节跳动网络技术有限公司 | 页面生成方法、装置、电子设备和计算机可读存储介质 |
CN110263279A (zh) * | 2019-05-08 | 2019-09-20 | 北京字节跳动网络技术有限公司 | 页面生成方法、装置、电子设备和计算机可读存储介质 |
CN110442419B (zh) * | 2019-08-15 | 2022-11-29 | 北京字节跳动网络技术有限公司 | Android应用的界面布局方法及装置 |
CN110442419A (zh) * | 2019-08-15 | 2019-11-12 | 北京字节跳动网络技术有限公司 | Android应用的界面布局方法及装置 |
CN111459570A (zh) * | 2020-03-30 | 2020-07-28 | 掌阅科技股份有限公司 | Pdf插件加载方法、电子设备和计算机存储介质 |
CN111459570B (zh) * | 2020-03-30 | 2023-03-17 | 掌阅科技股份有限公司 | Pdf插件加载方法、电子设备和计算机存储介质 |
CN111897469A (zh) * | 2020-07-06 | 2020-11-06 | 上海泛微网络科技股份有限公司 | 一种实时数据处理方法、装置、设备和存储介质 |
CN111813385A (zh) * | 2020-07-07 | 2020-10-23 | 赞同科技股份有限公司 | 一种基于Web应用的页面插件化方法、装置及设备 |
CN111813385B (zh) * | 2020-07-07 | 2023-09-22 | 赞同科技股份有限公司 | 一种基于Web应用的页面插件化方法、装置及设备 |
CN112632920A (zh) * | 2020-11-16 | 2021-04-09 | 腾讯科技(深圳)有限公司 | 一种链接处理方法、链接处理装置、终端设备及存储介质 |
US20230130527A1 (en) * | 2021-01-04 | 2023-04-27 | Capital One Services, Llc | Dynamic review of software updates after pull requests |
US12026509B2 (en) * | 2021-01-04 | 2024-07-02 | Capital One Services, Llc | Dynamic review of software updates after pull requests |
CN113076462A (zh) * | 2021-03-25 | 2021-07-06 | 恒安嘉新(北京)科技股份公司 | 网络会话数据查询方法、装置、设备及介质 |
CN113076462B (zh) * | 2021-03-25 | 2024-04-30 | 恒安嘉新(北京)科技股份公司 | 网络会话数据查询方法、装置、设备及介质 |
CN113065314B (zh) * | 2021-03-26 | 2023-02-28 | 山东英信计算机技术有限公司 | 一种基于xml文件格式的bios硬件适配方法及装置 |
CN113065314A (zh) * | 2021-03-26 | 2021-07-02 | 山东英信计算机技术有限公司 | 一种基于xml文件格式的bios硬件适配方法及装置 |
CN113342417A (zh) * | 2021-06-15 | 2021-09-03 | 京东数科海益信息科技有限公司 | 插件配置方法、装置和设备 |
CN114064662A (zh) * | 2022-01-13 | 2022-02-18 | 北京中交兴路信息科技有限公司 | 查询数据的方法、装置、电子设备及介质 |
CN114090523A (zh) * | 2022-01-19 | 2022-02-25 | 荣耀终端有限公司 | 电子设备及其xml文件的节点解析方法、介质 |
CN114595199A (zh) * | 2022-05-10 | 2022-06-07 | 太平金融科技服务(上海)有限公司 | 文件解析方法、装置、计算机设备和存储介质 |
CN116301831B (zh) * | 2023-03-20 | 2024-02-27 | 中国华能集团有限公司北京招标分公司 | 一种dp插件及其使用方法 |
CN116301831A (zh) * | 2023-03-20 | 2023-06-23 | 中国华能集团有限公司北京招标分公司 | 一种dp插件及其使用方法 |
CN116302076B (zh) * | 2023-05-18 | 2023-08-15 | 云账户技术(天津)有限公司 | 一种基于解析配置项表结构进行配置项配置的方法及装置 |
CN116302076A (zh) * | 2023-05-18 | 2023-06-23 | 云账户技术(天津)有限公司 | 一种基于解析配置项表结构进行配置项配置的方法及装置 |
Also Published As
Publication number | Publication date |
---|---|
CN105095348B (zh) | 2019-03-26 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN105095348B (zh) | 一种通过xml动态配置网站的方法 | |
Huck et al. | Jedi: Extracting and synthesizing information from the web | |
US7409401B2 (en) | Method and system for supporting multivalue attributes in a database system | |
US7505985B2 (en) | System and method of generating string-based search expressions using templates | |
US6513010B1 (en) | Method and apparatus for separating processing for language-understanding from an application and its functionality | |
NL1028923C2 (nl) | Werkwijze, toestel en software voor het extraheren van chemische gegevens. | |
US5630120A (en) | Method to help in optimizing a query from a relational data base management system | |
US5261093A (en) | Interactive relational database analysis with successive refinement steps in selection of ouput data from underlying database | |
US20060195420A1 (en) | System and method of joining data obtained from horizontally and vertically partitioned heterogeneous data stores using string-based location transparent search expressions | |
US8826142B2 (en) | Document handling in a web application | |
CN110147544A (zh) | 一种基于自然语言的指令生成方法、装置以及相关设备 | |
US5630114A (en) | Database management system embedded in an operating system command | |
CN111125439A (zh) | 一种xml数据处理方法、***和存储介质 | |
EP1222539A1 (en) | A software component-container framework for dynamic deployment of business logic components in a distributed object environment | |
ter Hofstede et al. | Exploiting fact verbalisation in conceptual information modelling | |
CN110311819A (zh) | 基于页面配置文件的页面自动生成和MIBs表生成方法、管理方法、设备端和管理*** | |
US20050267909A1 (en) | Storing multipart XML documents | |
Haidou | On the syntax and pragmatics interface: left-peripheral, medial and right-peripheral focus in Greek | |
Besemer et al. | FLUSH: a flexible lexicon design | |
Meng et al. | GLR parsing with multiple grammars for natural language queries | |
JP3995186B2 (ja) | 構文解析装置 | |
WO2002095616A1 (en) | Parsing system | |
Zeng et al. | Information retrieval based on conceptual network | |
Ward et al. | Oracle Call Interface Programmer's Guide, 11g Release 2 (11.2) E10646-12 | |
CN117874167A (zh) | 一种搜索对象的方法、***、设备和存储介质 |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
C06 | Publication | ||
PB01 | Publication | ||
C10 | Entry into substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
GR01 | Patent grant | ||
GR01 | Patent grant |