PageRenderTime 53ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/library/xslt/src/function/xm_xslt_transformation.e

http://github.com/gobo-eiffel/gobo
Specman e | 428 lines | 372 code | 37 blank | 19 comment | 27 complexity | 161546a8459b97f6d9131d74d82b879c MD5 | raw file
  1. note
  2. description:
  3. "Objects that implement the gexslt:transformation() function"
  4. library: "Gobo Eiffel XSLT Library"
  5. copyright: "Copyright (c) 2006-2018, Colin Adams and others"
  6. license: "MIT License"
  7. date: "$Date$"
  8. revision: "$Revision$"
  9. class XM_XSLT_TRANSFORMATION
  10. inherit
  11. XM_XPATH_SYSTEM_FUNCTION
  12. redefine
  13. pre_evaluate, create_iterator, check_static_type
  14. end
  15. XM_XPATH_NODE_FACTORY
  16. export {NONE} all end
  17. create
  18. make
  19. feature {NONE} -- Initialization
  20. make
  21. -- Establish invariant
  22. do
  23. name := "transformation"; namespace_uri := Gexslt_eiffel_type_uri
  24. fingerprint := Gexslt_transformation_function_type_code
  25. minimum_argument_count := 2
  26. maximum_argument_count := 7
  27. create arguments.make (7)
  28. arguments.set_equality_tester (expression_tester)
  29. initialized := True
  30. end
  31. feature -- Access
  32. item_type: XM_XPATH_ITEM_TYPE
  33. -- Data type of the expression, where known
  34. do
  35. Result := any_item
  36. end
  37. feature -- Status report
  38. required_type (argument_number: INTEGER): XM_XPATH_SEQUENCE_TYPE
  39. -- Type of argument number `argument_number'
  40. do
  41. inspect
  42. argument_number
  43. when 1 then
  44. create Result.make_single_string
  45. when 2 then
  46. if arguments.count = 7 then
  47. create Result.make_optional_node
  48. else
  49. create Result.make_single_node
  50. end
  51. when 3, 4 then
  52. create Result.make_optional_qname
  53. when 5 then
  54. create Result.make_qname_sequence
  55. when 6 then
  56. create Result.make_any_sequence
  57. when 7 then
  58. create Result.make_optional_string
  59. end
  60. end
  61. feature -- Optimization
  62. check_static_type (a_replacement: DS_CELL [detachable XM_XPATH_EXPRESSION]; a_context: XM_XPATH_STATIC_CONTEXT; a_context_item_type: detachable XM_XPATH_ITEM_TYPE)
  63. -- Perform static type-checking of `Current' and its subexpressions.
  64. do
  65. if attached {like static_context} a_context as l_static_context then
  66. static_context := l_static_context
  67. else
  68. static_context := Void
  69. end
  70. Precursor (a_replacement, a_context, a_context_item_type)
  71. end
  72. feature -- Evaluation
  73. create_iterator (a_context: XM_XPATH_CONTEXT)
  74. -- Iterator over the values of a sequence
  75. local
  76. l_result: XM_XSLT_TRANSFORMATION_RESULT
  77. l_builder: XM_XPATH_TREE_BUILDER
  78. l_config: XM_XSLT_CONFIGURATION
  79. l_tracer: detachable XM_XSLT_TRACE_LISTENER
  80. do
  81. last_iterator := Void
  82. last_error := Void
  83. check attached {XM_XSLT_EVALUATION_CONTEXT} a_context as l_context then
  84. evaluate_arguments (l_context)
  85. check attached transformer as l_transformer then
  86. if last_error /= Void then
  87. last_iterator := qname_value_iterator
  88. elseif initial_context = Void and l_transformer.initial_template = Void then
  89. create last_error.make_from_string ("An initial template is required when no source document is present",
  90. Gexslt_eiffel_type_uri, "NO_INITIAL_TEMPLATE", Static_error)
  91. last_iterator := qname_value_iterator
  92. else
  93. check attached static_context as l_static_context then
  94. create l_builder.make (Current, l_static_context.base_uri.full_reference, Void)
  95. create l_result.make_receiver (l_builder)
  96. l_config := l_transformer.configuration
  97. l_tracer := l_config.trace_listener
  98. l_config.set_trace_listener (Void)
  99. l_transformer.transform_document (initial_context, l_result)
  100. l_config.set_trace_listener (l_tracer)
  101. last_iterator := result_iterator
  102. end
  103. end
  104. end
  105. end
  106. end
  107. pre_evaluate (a_replacement: DS_CELL [detachable XM_XPATH_EXPRESSION]; a_context: XM_XPATH_STATIC_CONTEXT)
  108. -- Pre-evaluate `Current' at compile time.
  109. do
  110. a_replacement.put (Current)
  111. end
  112. feature {XM_XPATH_EXPRESSION} -- Restricted
  113. compute_cardinality
  114. -- Compute cardinality.
  115. do
  116. set_cardinality_one_or_more
  117. end
  118. feature {NONE} -- Implementation
  119. static_context: detachable XM_XSLT_EXPRESSION_CONTEXT
  120. -- Saved static context for base URI
  121. last_error: detachable XM_XPATH_ERROR_VALUE
  122. -- Last reported error
  123. transformer: detachable XM_XSLT_TRANSFORMER
  124. -- Transformer to run transformation
  125. initial_context: detachable XM_XPATH_NODE
  126. -- Optional initial context
  127. evaluate_arguments (a_context: XM_XSLT_EVALUATION_CONTEXT)
  128. -- Evaluate and validate arguments to function call.
  129. require
  130. last_error_is_void: last_error = Void
  131. a_context_not_void: a_context /= Void
  132. local
  133. l_argument: DS_CELL [detachable XM_XPATH_ITEM]
  134. l_source: XM_XSLT_URI_SOURCE
  135. l_factory: XM_XSLT_TRANSFORMER_FACTORY
  136. do
  137. create l_argument.make (Void)
  138. arguments.item (1).evaluate_item (l_argument, a_context)
  139. check attached l_argument.item as l_argument_item_1 then
  140. if l_argument_item_1.is_error then
  141. last_error := l_argument_item_1.error_value
  142. else
  143. create l_source.make (l_argument_item_1.as_string_value.string_value)
  144. check attached a_context.transformer as l_context_transformer then
  145. l_factory := l_context_transformer.transformer_factory
  146. check attached static_context as l_static_context then
  147. l_factory.create_new_transformer (l_source, l_static_context.base_uri)
  148. if attached l_factory.last_error_message as l_last_error_message then
  149. check was_error: l_factory.was_error end
  150. create last_error.make_from_string (l_last_error_message, Gexslt_eiffel_type_uri, "COMPILE_FAILED", Static_error)
  151. else
  152. transformer := l_factory.created_transformer
  153. create l_argument.make (Void)
  154. arguments.item (2).evaluate_item (l_argument, a_context)
  155. if not attached l_argument.item as l_argument_item_2 then
  156. initial_context := Void
  157. elseif l_argument_item_2.is_error then
  158. last_error := l_argument_item_2.error_value
  159. else
  160. initial_context := l_argument_item_2.as_node
  161. end
  162. if arguments.count > 2 then
  163. evaluate_optional_arguments (a_context)
  164. end
  165. end
  166. end
  167. end
  168. end
  169. end
  170. ensure
  171. no_error_implies_transformer_not_void: last_error = Void implies transformer /= Void
  172. end
  173. evaluate_optional_arguments (a_context: XM_XSLT_EVALUATION_CONTEXT)
  174. -- Evaluate arguments beyond second argument.
  175. require
  176. last_error_is_void: last_error = Void
  177. a_context_not_void: a_context /= Void
  178. transformer_not_void: transformer /= Void
  179. seven_arguments: arguments.count = 7
  180. local
  181. l_argument: DS_CELL [detachable XM_XPATH_ITEM]
  182. l_iterator, l_iterator_2: XM_XPATH_SEQUENCE_ITERATOR [XM_XPATH_ITEM]
  183. do
  184. check precondition_transformer_not_void: attached transformer as l_transformer then
  185. create l_argument.make (Void)
  186. arguments.item (3).evaluate_item (l_argument, a_context)
  187. if attached l_argument.item as l_argument_item then
  188. if attached l_argument_item.error_value as l_error_value then
  189. check is_error: l_argument_item.is_error end
  190. last_error := l_error_value
  191. else
  192. l_transformer.set_initial_template (l_argument_item.as_qname_value.expanded_name)
  193. end
  194. end
  195. if not is_error then
  196. create l_argument.make (Void)
  197. arguments.item (4).evaluate_item (l_argument, a_context)
  198. if attached l_argument.item as l_argument_item then
  199. if attached l_argument_item.error_value as l_error_value then
  200. check is_error: l_argument_item.is_error end
  201. last_error := l_error_value
  202. else
  203. l_transformer.set_initial_mode (l_argument_item.as_qname_value.expanded_name)
  204. end
  205. end
  206. end
  207. if not is_error then
  208. arguments.item (5).create_iterator (a_context)
  209. check postcondition_of_create_iterator: attached arguments.item (5).last_iterator as l_last_iterator then
  210. l_iterator := l_last_iterator
  211. if l_iterator.is_error then
  212. last_error := l_iterator.error_value
  213. else
  214. arguments.item (6).create_iterator (a_context)
  215. check postcondition_of_create_iterator: attached arguments.item (6).last_iterator as l_last_iterator_2 then
  216. l_iterator_2 := l_last_iterator_2
  217. if l_iterator_2.is_error then
  218. last_error := l_iterator.error_value
  219. else
  220. process_parameters (l_iterator, l_iterator_2)
  221. end
  222. end
  223. end
  224. end
  225. end
  226. if not is_error then
  227. arguments.item (7).create_iterator (a_context)
  228. check postcondition_of_create_iterator: attached arguments.item (7).last_iterator as l_last_iterator then
  229. l_iterator := l_last_iterator
  230. if l_iterator.is_error then
  231. last_error := l_iterator.error_value
  232. else
  233. l_iterator.start
  234. if l_iterator.is_error then
  235. last_error := l_iterator.error_value
  236. elseif not l_iterator.after then
  237. create last_error.make_from_string ("Feature name " + l_iterator.item.string_value + " is not recognized",
  238. Gexslt_eiffel_type_uri, "UNRECOGNIZED_FEATURE", Dynamic_error)
  239. end
  240. end
  241. end
  242. end
  243. end
  244. end
  245. process_parameters (a_names, a_values: XM_XPATH_SEQUENCE_ITERATOR [XM_XPATH_ITEM])
  246. -- Process global stylesheet parameters.
  247. require
  248. a_names_not_void: a_names /= Void
  249. a_names_before: a_names.before
  250. a_values_not_void: a_values /= Void
  251. a_values_before: a_values.before
  252. local
  253. l_name: XM_XPATH_QNAME_VALUE
  254. l_value: STRING
  255. do
  256. from
  257. a_names.start
  258. a_values.start
  259. until
  260. last_error /= Void or a_names.after or a_values.after
  261. loop
  262. if a_names.is_error then
  263. last_error := a_names.error_value
  264. elseif a_values.is_error then
  265. last_error := a_values.error_value
  266. else
  267. l_name := a_names.item.as_qname_value
  268. l_value := a_values.item.string_value
  269. check attached transformer as l_transformer then
  270. l_transformer.set_xpath_parameter (l_value, l_name.expanded_name)
  271. end
  272. a_names.forth
  273. a_values.forth
  274. end
  275. end
  276. if last_error = Void then
  277. if not a_names.after then
  278. create last_error.make_from_string ("Not enough parameter values supplied",
  279. Gexslt_eiffel_type_uri, "PARAMETER_MISMATCH", Dynamic_error)
  280. elseif not a_values.after then
  281. create last_error.make_from_string ("Too many parameter values supplied",
  282. Gexslt_eiffel_type_uri, "PARAMETER_MISMATCH", Dynamic_error)
  283. end
  284. end
  285. end
  286. result_iterator: XM_XPATH_ARRAY_LIST_ITERATOR [XM_XPATH_ITEM]
  287. -- Iterator over result documents
  288. require
  289. last_error_is_void: last_error = Void
  290. transformer_not_void: transformer /= Void
  291. local
  292. l_list: DS_ARRAYED_LIST [XM_XPATH_NODE]
  293. l_builder: XM_XPATH_BUILDER
  294. do
  295. check precondition_transformer_not_void: attached transformer as l_transformer then
  296. if l_transformer.is_error then
  297. last_error := l_transformer.last_error
  298. Result := qname_value_iterator
  299. else
  300. create l_list.make (1)
  301. check
  302. attached l_transformer.principal_result as l_principal_result
  303. attached l_principal_result.principal_receiver as l_principal_receiver
  304. then
  305. l_builder := l_principal_receiver.as_builder
  306. if attached l_builder.current_root as l_current_root then
  307. l_list.put_first (l_current_root)
  308. end
  309. create {XM_XPATH_ARRAY_NODE_LIST_ITERATOR} Result.make (l_list)
  310. end
  311. end
  312. end
  313. ensure
  314. result_not_void: Result /= Void
  315. end
  316. qname_value_iterator: XM_XPATH_ARRAY_LIST_ITERATOR [XM_XPATH_ITEM]
  317. -- Iterator over components of `last_error'
  318. require
  319. last_error_not_void: last_error /= Void
  320. local
  321. l_uri, l_local_part, l_prefix: STRING
  322. l_desc: XM_XPATH_STRING_VALUE
  323. l_value: XM_XPATH_SEQUENCE_ITERATOR [XM_XPATH_ITEM]
  324. l_qname: XM_XPATH_QNAME_VALUE
  325. l_name_code: INTEGER
  326. l_list: DS_ARRAYED_LIST [XM_XPATH_ITEM]
  327. do
  328. check precondition_last_error_not_void: attached last_error as l_last_error then
  329. l_uri := l_last_error.namespace_uri
  330. l_local_part := l_last_error.code
  331. create l_desc.make (l_last_error.description)
  332. l_value := l_last_error.value
  333. l_prefix := arbitrary_qname_prefix (l_uri)
  334. if shared_name_pool.is_name_code_allocated (l_prefix, l_uri, l_local_part) then
  335. l_name_code := shared_name_pool.name_code (l_prefix, l_uri, l_local_part)
  336. else
  337. shared_name_pool.allocate_name (l_prefix, l_uri, l_local_part)
  338. l_name_code := shared_name_pool.last_name_code
  339. end
  340. create l_qname.make (l_name_code)
  341. create l_list.make_default
  342. l_list.put_first (l_qname)
  343. l_list.put_last (l_desc)
  344. from l_value.start until l_value.after loop
  345. l_list.force_last (l_value.item)
  346. l_value.forth
  347. end
  348. create Result.make (l_list)
  349. end
  350. ensure
  351. result_not_void: Result /= Void
  352. end
  353. arbitrary_qname_prefix (a_uri: STRING): STRING
  354. -- Arbitrary XML prefix
  355. require
  356. a_uri_not_void: a_uri /= Void
  357. a_uri_not_empty: not a_uri.is_empty
  358. local
  359. l_cursor: DS_ARRAYED_LIST_CURSOR [INTEGER]
  360. i: INTEGER
  361. l_result: detachable STRING
  362. do
  363. -- First see if we already have a binding in the stylesheet
  364. check attached static_context as l_static_context then
  365. from l_cursor := l_static_context.style_element.namespace_codes_in_scope.new_cursor; l_cursor.start until l_cursor.after loop
  366. if STRING_.same_string (shared_name_pool.uri_from_namespace_code (l_cursor.item), a_uri) then
  367. l_result := shared_name_pool.prefix_from_namespace_code (l_cursor.item)
  368. l_cursor.go_after
  369. else
  370. l_cursor.forth
  371. end
  372. end
  373. end
  374. -- Maybe the namespace is already known to the name pool
  375. if l_result = Void then
  376. l_result := shared_name_pool.suggested_prefix_for_uri (a_uri)
  377. if l_result = Void then
  378. from i := 0
  379. l_result := "ns" + i.out
  380. until not shared_name_pool.is_code_for_prefix_allocated (l_result) loop
  381. i := i + 1
  382. l_result := "ns" + i.out
  383. end
  384. end
  385. end
  386. Result := l_result
  387. ensure
  388. chosen_prefix_not_void: Result /= Void
  389. chosen_prefix_not_empty: not Result.is_empty
  390. end
  391. end