旧版 XML 包装器实施

Page Contents

Note:

不推荐使用旧的 XML 包装器. FreeMarker 2.3 引入了对新 XML 处理模型的支持。为此,引入了一个新的 XML 包装程序包freemarker.ext.dom。对于新用法,我们鼓励您使用它。它记录在XML 处理指南部分中。

freemarker.ext.xml.NodeListModel类提供了用于包装表示为节点树的 XML 文档的模板模型。每个节点列表可以包含零个或多个 XML 节点(文档,元素,文本,处理指令,Comments,实体引用,CDATA 节等)。节点列表使用以下语义实现以下模板模型接口:

TemplateScalarModel

当用作标量时,节点列表将呈现表示其包含的节点的 XML 片段。这使得在 XML 到 XML 转换模板中使用非常方便。

TemplateCollectionModel

当用作带有list指令的集合时,它将仅枚举其节点。每个节点将作为由单个节点组成的新节点列表返回。

TemplateSequenceModel

当用作序列时,它将返回第 i 个节点作为由单个请求节点组成的新节点列表。即要返回<book>元素的第三个<chapter>元素,请使用以下命令(注意索引从零开始):

<#assign thirdChapter = xmldoc.book.chapter[2]>

TemplateHashModel

当用作哈希时,它基本上用于遍历子级。也就是说,如果您有一个名为book的节点列表,该节点列表包装了具有多个章节的元素节点,则book.chapter将产生一个包含该 book 元素的所有章节元素的节点列表。 at 符号用于引用属性:book.@title产生具有单个属性节点的节点列表,该节点列表是 book 元素的 title 属性。

重要的是要意识到这样的结果,例如,如果book没有chapter -s,则book.chapter是空序列,因此xmldoc.book.chapter??false,它将始终是true!同样,xmldoc.book.somethingTotallyNonsense??也不是false。要检查是否未找到子代,请使用xmldoc.book.chapter?size == 0

哈希还定义了几个“魔术键”。所有这些键均以下划线开头。最值得注意的是_text键,该键检索节点的文本:${book.@title._text}将属性值渲染到模板中。类似地,_name将检索元素或属性的名称。 *_allChildren返回节点列表中所有元素的所有直接子元素,而@*_allAttributes返回节点列表中元素的所有属性。还有更多这样的键;这是所有哈希键的详细摘要:

Key nameEvaluates to
*_children当前节点的所有直接元素子代(非递归)。适用于元素和文档节点。
@*_attributes当前节点的所有属性。仅适用于元素。
@attributeName当前节点的命名属性。适用于元素,文档类型和处理说明。在 doctypes 上,它支持publicIdsystemIdelementName属性。根据处理指令,它支持targetdata属性,以及数据中以name="value"对指定的任何其他属性名称。 doctype 和处理指令的属性节点是合成的,因此没有父级。但是请注意,@*不能对文档类型或处理指令进行操作。
_ancestor所有祖先,直到当前节点的根元素(递归)。适用于与_parent相同的节点类型。
_ancestorOrSelf当前节点的所有祖先加上当前节点。适用于与_parent相同的节点类型。
_cname当前节点的规范名称(名称空间 URI 本地名称),每个节点一个字符串(非递归)。适用于元素和属性
_content当前节点的完整内容,包括子元素,文本,实体引用和处理指令(非递归)。适用于元素和文档。
_descendant当前节点的所有递归子元素子级。适用于文档和元素节点。
_descendantOrSelf当前节点加上当前节点的所有递归后代元素子元素。适用于文档和元素节点。
_document当前节点所属的所有文档。适用于除文本之外的所有节点。
_doctype当前节点的文档类型。仅适用于文档节点。
_filterType是按类型过滤的模板方法模型。调用时,它将产生一个节点列表,该列表仅包含那些类型与作为参数传递的类型之一匹配的当前节点。您应该向此方法传递任意数量的字符串,其中包含要保留的类型的名称。有效的类型名称是:“属性”,“ cdata”,“Comments”,“文档”,“ documentType”,“ element”,“ entity”,“ entityReference”,“ processingInstruction”,“ text”。
_name当前节点的名称,每个节点一个字符串(非递归)。适用于元素和属性(返回其本地名称),实体,处理指令(返回其目标),文档类型(返回其公共 ID)
_nsprefix当前节点的名称空间前缀,每个节点一个字符串(非递归)。适用于元素和属性
_nsuri当前节点的名称空间 URI,每个节点一个字符串(非递归)。适用于元素和属性
_parent当前节点的父元素。适用于元素,属性,Comments,实体,处理指令。
_qname[namespacePrefix:]localName形式的当前节点的合格名称,每个节点一个字符串(非递归)。适用于元素和属性
_registerNamespace(prefix, uri)为当前节点列表和派生自当前节点列表的所有节点列表注册具有指定前缀和 URI 的 XML 名称空间。注册后,可以使用nodelist["prefix:localname"]nodelist["@prefix:localname"]语法来访问其名称是名称空间范围的元素和属性。请注意,名称空间前缀不必与 XML 文档本身使用的实际前缀匹配,因为名称空间仅通过其 URI 进行比较。
_text当前节点的文本,每个节点一个字符串(非递归)。适用于元素,属性,Comments,处理指令(返回其数据)和 CDATA 部分。保留的 XML 字符(“ <”和“&”)不会转义。
_type返回一个节点列表,其中每个节点包含一个描述该节点类型的字符串。可能的节点类型名称是:“属性”,“ cdata”,“Comments”,“文档”,“ documentType”,“元素”,“实体”,“ entityReference”,“ processingInstruction”,“文本”。如果节点的类型未知,则返回“未知”。
_unique当前节点的副本,仅保留每个节点的第一个匹配项,从而消除重复项。通过应用上树遍历_parent_ancestor_ancestorOrSelf_document可以在节点列表中发生重复。即foo._children._parent将返回一个节点列表,该列表在 foo 中具有重复的节点-每个节点的出现次数等于其子节点的数量。在这些情况下,请使用foo._children._parent._unique消除重复项。适用于所有节点类型。
任何其他键名称与关键字匹配的当前节点的子元素。这样可以方便地以book.chapter.title样式语法遍历子级。请注意,nodeset.childname在技术上等效于nodeset("childname"),但是写起来更短并且求值速度更快。适用于文档和元素节点。

TemplateMethodModel

当用作方法模型时,它返回节点列表,该节点列表是对节点列表的当前内容上的 XPath 表达式求值的结果。要使用此功能,您的 Classpath 中必须具有Jaxen库。例如:

<#assign firstChapter=xmldoc("//chapter[first()]")>

Namespace handling

为了遍历具有名称空间范围名称的子元素,可以在节点列表中注册名称空间前缀。您可以使用 Java 进行操作,

public void registerNamespace(String prefix, String uri);

方法,或使用

${nodelist._registerNamespace(prefix, uri)}

句法。从那里开始,您可以通过语法在由特定 URI 表示的命名空间中引用子元素。

nodelist["prefix:localName"]

and

nodelist["@prefix:localName"]

以及在 XPath 表达式中使用这些名称空间前缀。向节点列表注册的命名空间将传播到从原始节点列表派生的所有节点列表。还请注意,名称空间仅通过其 URI 进行匹配,因此您可以安全地使用模板中名称空间的前缀,该前缀与实际 XML 文档中的前缀不同-前缀只是模板和模板中 URI 的本地别名。在 XML 文档中。