@@ -3,6 +3,40 @@ local C14n = {}
33local libxml2 = require (" xmlua.libxml2" )
44local ffi = require (" ffi" )
55
6+ local DEFAULT_MODE = " C14N_EXCLUSIVE_1_0"
7+
8+ local Attribute
9+ local AttributeDeclaration
10+ local CDATASection
11+ local Comment
12+ local Document
13+ local DocumentFragment
14+ local DocumentType
15+ local Element
16+ local ElementDeclaration
17+ local EntityDeclaration
18+ local NamespaceDeclaration
19+ local Notation
20+ local ProcessingInstruction
21+ local Text
22+
23+ function C14n .lazy_load ()
24+ Attribute = require (" xmlua.attribute" )
25+ AttributeDeclaration = require (" xmlua.attribute-declaration" )
26+ Text = require (" xmlua.text" )
27+ CDATASection = require (" xmlua.cdata-section" )
28+ Comment = require (" xmlua.comment" )
29+ Document = require (" xmlua.document" )
30+ DocumentFragment = require (" xmlua.document-fragment" )
31+ DocumentType = require (" xmlua.document-type" )
32+ Element = require (" xmlua.element" )
33+ ElementDeclaration = require (" xmlua.element-declaration" )
34+ EntityDeclaration = require (" xmlua.entity-declaration" )
35+ NamespaceDeclaration = require (" xmlua.namespace-declaration" )
36+ Notation = require (" xmlua.notation" )
37+ ProcessingInstruction = require (" xmlua.processing-instruction" )
38+ end
39+
640
741
842local C14N_MODES = {
81115-- @param with_comments if truthy, comments will be included (default: false)
82116-- @return string containing canonicalized xml
83117function C14n :c14n_save (nodes , mode , inclusive_ns_prefixes , with_comments )
84- if mode == nil then -- default is exclusive 1.0
85- mode = " C14N_EXCLUSIVE_1_0 "
118+ if mode == nil then
119+ mode = DEFAULT_MODE
86120 end
87121 with_comments = with_comments and 1 or 0 -- default = not including comments
88122
@@ -103,4 +137,121 @@ end
103137
104138
105139
140+ local wrap_raw_node do
141+ -- order is according to the constant value of xmlElementType enum in libxml2
142+ local type_generators = setmetatable ({
143+ [ffi .C .XML_ELEMENT_NODE ] = function (document , raw_node )
144+ return Element .new (document , raw_node )
145+ end ,
146+ [ffi .C .XML_ATTRIBUTE_NODE ] = function (document , raw_node )
147+ return Attribute .new (document , raw_node )
148+ end ,
149+ [ffi .C .XML_TEXT_NODE ] = function (document , raw_node )
150+ return Text .new (document , raw_node )
151+ end ,
152+ [ffi .C .XML_CDATA_SECTION_NODE ] = function (document , raw_node )
153+ return CDATASection .new (document , raw_node )
154+ end ,
155+ [ffi .C .XML_ENTITY_REF_NODE ] = function (document , raw_node )
156+ error (" XML_ENTITY_REF_NODE not implemented" ) -- TODO: implement
157+ end ,
158+ [ffi .C .XML_ENTITY_NODE ] = function (document , raw_node )
159+ error (" XML_ENTITY_NODE not implemented" ) -- TODO: implement
160+ end ,
161+ [ffi .C .XML_PI_NODE ] = function (document , raw_node )
162+ return ProcessingInstruction .new (document , raw_node )
163+ end ,
164+ [ffi .C .XML_COMMENT_NODE ] = function (document , raw_node )
165+ return Comment .new (document , raw_node )
166+ end ,
167+ [ffi .C .XML_DOCUMENT_NODE ] = function (document , raw_node )
168+ return Document .new (raw_node )
169+ end ,
170+ [ffi .C .XML_DOCUMENT_TYPE_NODE ] = function (document , raw_node )
171+ return DocumentType .new (document , raw_node )
172+ end ,
173+ [ffi .C .XML_DOCUMENT_FRAG_NODE ] = function (document , raw_node )
174+ return DocumentFragment .new (document , raw_node )
175+ end ,
176+ [ffi .C .XML_NOTATION_NODE ] = function (document , raw_node )
177+ return Notation .new (document , raw_node )
178+ end ,
179+ [ffi .C .XML_HTML_DOCUMENT_NODE ] = function (document , raw_node )
180+ error (" XML_HTML_DOCUMENT_NODE not implemented" ) -- TODO: implement
181+ end ,
182+ [ffi .C .XML_DTD_NODE ] = function (document , raw_node )
183+ error (" XML_DTD_NODE not implemented" ) -- TODO: implement
184+ end ,
185+ [ffi .C .XML_ELEMENT_DECL ] = function (document , raw_node )
186+ return ElementDeclaration .new (document , raw_node )
187+ end ,
188+ [ffi .C .XML_ATTRIBUTE_DECL ] = function (document , raw_node )
189+ return AttributeDeclaration .new (document , raw_node )
190+ end ,
191+ [ffi .C .XML_ENTITY_DECL ] = function (document , raw_node )
192+ return EntityDeclaration .new (document , raw_node )
193+ end ,
194+ [ffi .C .XML_NAMESPACE_DECL ] = function (document , raw_node )
195+ return NamespaceDeclaration .new (document , raw_node )
196+ end ,
197+ [ffi .C .XML_XINCLUDE_START ] = function (document , raw_node )
198+ error (" XML_XINCLUDE_START not implemented" ) -- TODO: implement
199+ end ,
200+ [ffi .C .XML_XINCLUDE_END ] = function (document , raw_node )
201+ error (" XML_XINCLUDE_END not implemented" ) -- TODO: implement
202+ end ,
203+ [ffi .C .XML_DOCB_DOCUMENT_NODE ] = function (document , raw_node )
204+ error (" XML_DOCB_DOCUMENT_NODE not implemented" ) -- TODO: implement
205+ end ,
206+ }, {
207+ __index = function (self , key )
208+ error (" Unknown node type: " .. tostring (key ))
209+ end
210+ })
211+
212+ function wrap_raw_node (document , raw_node )
213+ if raw_node == ffi .NULL then
214+ return nil
215+ end
216+ return type_generators [tonumber (raw_node .type )](document , raw_node )
217+ end
218+ end
219+
220+
221+
222+ --- Canonicalise an xmlDocument or set of elements.
223+ -- @param self xmlDoc from which to canonicalize elements
224+ -- @param callback function to determine if a node should be included in the canonicalized output.
225+ -- Signature: `boolean = function(node, parent)`
226+ -- @param mode any of C14N_1_0, C14N_EXCLUSIVE_1_0 (default), C14N_1_1
227+ -- @param inclusive_ns_prefixes array, or space-separated string, of namespace prefixes to include
228+ -- @param with_comments if truthy, comments will be included (default: false)
229+ -- @return string containing canonicalized xml
230+ function C14n :c14n_execute (callback , mode , inclusive_ns_prefixes , with_comments )
231+ if mode == nil then
232+ mode = DEFAULT_MODE
233+ end
234+ with_comments = with_comments and 1 or 0 -- default = not including comments
235+ assert (type (callback ) == " function" , " callback must be a function" )
236+
237+ -- wrap the callback to pass wrapped objects, and return 1 or 0
238+ local cbwrapper = function (_ , nodePtr , parentPtr )
239+ return callback (wrap_raw_node (self , nodePtr ), wrap_raw_node (self , parentPtr )) and 1 or 0
240+ end
241+
242+ mode = assert (C14N_MODES_LOOKUP [mode ], " mode must be a valid C14N mode constant" )
243+ local prefixes = getNamespacePrefixArray (inclusive_ns_prefixes )
244+ local buffer = libxml2 .xmlBufferCreate ()
245+ local output_buffer = libxml2 .xmlOutputBufferCreate (buffer )
246+
247+ local success = libxml2 .xmlC14NExecute (self .document , cbwrapper , nil , mode ,
248+ prefixes , with_comments , output_buffer )
249+
250+ if success < 0 then
251+ return nil , " failed to generate C14N string"
252+ end
253+ return libxml2 .xmlBufferGetContent (buffer )
254+ end
255+
256+
106257return C14n
0 commit comments