@@ -328,8 +328,8 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
328328 public serialize ( adaptor : LiteAdaptor , node : LiteElement , xml : boolean = false ) : string {
329329 const SELF_CLOSING = ( this . constructor as typeof LiteParser ) . SELF_CLOSING ;
330330 const tag = adaptor . kind ( node ) ;
331- const attributes = adaptor . allAttributes ( node ) . map (
332- ( x : AttributeData ) => x . name + '="' + this . protectAttribute ( x . value ) + '"'
331+ const attributes = this . allAttributes ( adaptor , node , xml ) . map (
332+ ( x ) => x . name + '="' + this . protectAttribute ( x . value , xml ) + '"'
333333 ) . join ( ' ' ) ;
334334 const content = this . serializeInner ( adaptor , node , xml ) ;
335335 const html =
@@ -341,6 +341,7 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
341341 /**
342342 * @param {LiteAdaptor } adaptor The adaptor for managing nodes
343343 * @param {LiteElement } node The node whose innerHTML is needed
344+ * @param {boolean } xml True if XML rules should be used (e.g., self-closing tags)
344345 * @return {string } The serialized element (like innerHTML)
345346 */
346347 public serializeInner ( adaptor : LiteAdaptor , node : LiteElement , xml : boolean = false ) : string {
@@ -356,15 +357,54 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
356357 } ) . join ( '' ) ;
357358 }
358359
360+ /**
361+ * @param {LiteAdaptor } adaptor The adaptor for managing nodes
362+ * @param {LiteElement } node The node to serialize
363+ * @param {boolean } xml True when producing XML, false for HTML
364+ * @return {AttributeData[] } The attribute list
365+ */
366+ protected allAttributes ( adaptor : LiteAdaptor , node : LiteElement , xml : boolean ) : AttributeData [ ] {
367+ let attributes = adaptor . allAttributes ( node ) ;
368+ const kind = adaptor . kind ( node ) ;
369+ if ( ! xml || ( kind !== 'svg' && kind !== 'math' && kind !== 'html' ) ) {
370+ return attributes ;
371+ }
372+ //
373+ // Check for existance of xmlns attribute
374+ //
375+ for ( const { name} of attributes ) {
376+ if ( name === 'xmlns' ) {
377+ return attributes ;
378+ }
379+ }
380+ //
381+ // Add one of it is missing
382+ //
383+ attributes . push ( {
384+ name : 'xmlns' ,
385+ value : ( {
386+ svg : 'http://www.w3.org/2000/svg' ,
387+ math : 'http://www.w3.org/1998/Math/MathML' ,
388+ html : 'http://www.w3.org/1999/xhtml'
389+ } ) [ kind ]
390+ } ) ;
391+ return attributes ;
392+ }
393+
359394 /**
360395 * @param {string } text The attribute value to be HTML escaped
396+ * @param {boolean } xml True if XML rules are to be used
361397 * @return {string } The string with " replaced by entities
362398 */
363- public protectAttribute ( text : string ) : string {
399+ public protectAttribute ( text : string , xml : boolean ) : string {
364400 if ( typeof text !== 'string' ) {
365401 text = String ( text ) ;
366402 }
367- return text . replace ( / & / g, '&' ) . replace ( / " / g, '"' ) ;
403+ text = text . replace ( / & / g, '&' ) . replace ( / " / g, '"' ) ;
404+ if ( xml ) {
405+ text = text . replace ( / < / g, '<' ) . replace ( / > / g, '>' ) ;
406+ }
407+ return text ;
368408 }
369409
370410 /**
0 commit comments