Matthew Note

XSLT and XPATH

xslt

这次是为了用xslt来转换一个xml所以临时学习了下xslt

call-template和apply-templates

对xml模板 来说,name属性是很关键的 call-template /apply-template 的name必须要和模板的name相对应。模板相当于一个函数,可以暂时这么看。而name相当于函数名称.

简单说apply是应用,call是调用。
用apply时,引擎自动搜索与当前select指定xpath的匹配节点相匹配的template(该template必须有属性match)并使用该template进行处理,此时需要指定的是select的path。
用call时就跟其它语言调用函数一样,必须指定name属性,相应的,该template必须有name属性,当然,也可以在这时with-param(当然相应的模板中有对应的param才行,不过这个不强制要求)。

  1. 从名字区分:call-template,一次只对一个node名字有效;而apply-templates,注意是是复数,所以这个是对所有符合条件的node有效。
  2. 从手法上:call-template,手段是通过name;apply-templates手段是通过match。

  3. 使用apply调用的模板, 其中的上下文节点是与之匹配的节点。使用call调用的模板, 它没有上下文节点,参数通过param进行传递

xpath

xsl:iftest,一般对象的select都是一个xpath的表达式

  • name()函数可以用来取当前element的名字
  • text()可以取当前element的内容
  • count()统计element个数
  • 一个xpath可以包含一些条件例如$resource_type[@external = 'true'],表示attribute有externel且为true的节点
1
2
3
4
5
6
7
8
9
10
11
12
13
<xsl:element name="{name($resource_type)}">
<xsl:attribute name="count">
<xsl:value-of select="count($resource_type)" />
</xsl:attribute>
<xsl:if test="count($resource_type[@external = 'true']) != 0">
<xsl:element name="externalServer">
<xsl:attribute name="count">
<xsl:value-of select="count($resource_type[@external= 'true'])" />
</xsl:attribute>
</xsl:element>
</xsl:if>
</xsl:element>

parser

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
34
#!/usr/bin/env python3
# coding=utf-8
# Created Time: 2016-06-20
__author__ = 'Matthew Gao'
import lxml.etree as ET
import pprint
def parse():
pp = pprint.PrettyPrinter(indent=4)
xml_filename = 'amc_one_of_everything.xml'
xsl_filename = 'phonehometranslator.xsl'
dom = ET.parse(xml_filename)
xslt = ET.parse(xsl_filename)
transform = ET.XSLT(xslt)
newdom = transform(dom)
# print(ET.tostring(newdom, pretty_print=True))
pp.pprint(ET.tostring(newdom, pretty_print=True).decode())
print(transform.error_log)
for entry in transform.error_log:
print('message from line %s, col %s: %s' % (entry.line, entry.column, entry.message))
print('domain: %s (%d)' % (entry.domain_name, entry.domain))
print('type: %s (%d)' % (entry.type_name, entry.type))
print('level: %s (%d)' % (entry.level_name, entry.level))
print('filename: %s' % entry.filename)
if __name__ == "__main__":
parse()

调试

有人会说用来调试,但是这个在解析出错的时候似乎帮助不大,有些xslt的编辑器可以调试,但是都是付费的,所以没有具体尝试