How to insert elements into character content using Closure XML?

I need to convert all characters | for tags in all text blocks of a large XML file. That is, whenever I found

<test att="one|two">content | something more | and done</test> 

I need to convert to

 <test att="one|two">content <bar/> something more <bar/> and done</test> 

Please note that | can also occur in attribute values, in which case they must be preserved unchanged. After reading the Transforming slide in the overview part of the SAX Overview of the CXML documentation, I wrote

 (defclass preproc (cxml:sax-proxy) ()) (defmethod sax:characters ((handler preproc) data) (call-next-method handler (cl-ppcre:regex-replace "\\|" data "<bar/>"))) 

But of course, it creates a string (escaped), not a tag in the final XML.

 WML> (cxml:parse "<test>content | ola</test>" (make-instance 'preproc :chained-handler (cxml:make-string-sink))) 
 <?xml version="1.0" encoding="UTF-8"?> <test>content &lt;bar/&gt; ola</test>" 

Any idea or directions?

+1
source share
1 answer

The handler does not call the parser, but it processes the parsed values. Thus, instead of creating a string containing <bar /> , you should call a method that would be called if <bar /> was actually encountered. In this case, if the document really had

 content <bar/> ola 

inside the test element, then there would be calls:

 (sax:characters handler "content ") (sax:start-element handler nil nil "bar" '()) (sax:end-element handler nil nil "bar" (sax:characters handler " ola") 

So all you have to do is split the string by the character | (you can use CL-PPCRE to do this if you want, although there may be easier solutions) and then make a next-method call for each part of the line and calls sax: start-element and sax: end-element between:

 (defmethod sax:characters ((handler preproc) data) (let ((parts (cl-ppcre:split "\\|" data))) ;; check this on edge cases, though, eg, "", "|", "a|", strings ;; without any "|", etc. (call-next-method handler (pop parts)) (dolist (part parts) (sax:start-element handler nil nil "bar" '()) (sax:end-element handler nil nil "bar") (call-next-method handler part)))) 

 (cxml:parse "<test>content | ola</test>" (make-instance 'preproc :chained-handler (cxml:make-string-sink))) ;=> ; "<?xml version=\"1.0\" encoding=\"UTF-8\"?> ; <test>content <bar/> ola</test>" 
+2
source

Source: https://habr.com/ru/post/1206176/


All Articles