2013-02-02 13 views
5

Sto cercando di memorizzare l'input dell'utente in un documento XML sul lato client (javascript) e trasmetterlo al server per la persistenza.Rimozione di caratteri non validi da XML prima di serializzarli con XMLSerializer()

Un utente, ad esempio, incollato nel testo che includeva un carattere STX (0x2). XMLSerializer non ha eseguito l'escape del carattere STX e pertanto non è stato serializzato in XML ben formato. O forse la chiamata .attr() avrebbe dovuto essere sfuggita al carattere STX, ma in entrambi i casi è stato generato un XML non valido.

sto trovando l'uscita di In-Browser XMLSerializer() non è sempre ben formato, (e non ha nemmeno soddisfare proprio DOMParser del browser()

Questo esempio mostra che il carattere STX è non adeguatamente codificata dal XMLSerializer():

> doc = $.parseXML('<?xml version="1.0" encoding="utf-8" ?>\n<elem></elem>'); 
    #document 
> $(doc).find("elem").attr("someattr", String.fromCharCode(0x2)); 
    [ <elem someattr=​"">​</elem>​ ] 
> serializedDoc = new XMLSerializer().serializeToString(doc); 
    "<?xml version="1.0" encoding="utf-8"?><elem someattr=""/></elem>" 
> $.parseXML(serializedDoc); 
    Error: Invalid XML: <?xml version="1.0" encoding="utf-8"?><elem someattr=""/></elem> 

Come dovrei costruire un documento XML nel browser (con params determinati dall'utente-input arbitrario) in modo tale che sarà sempre ben formato (tutto correttamente sfuggito)? Non è necessario supportare IE8 o IE7

(E sì, convalido il codice XML sul lato server, ma se il browser consegna al server un documento che non è ben formato, il meglio che il server può fare è rifiutarlo, il che non è così utile per i poveri utente)

+0

Non sono sicuro che ci sia qualcosa di molto più semplice che passare attraverso la stringa sorgente carattere per carattere, traducendo le entità in base alle necessità. – Pointy

+0

Non mi fiderei di farlo (non conosco abbastanza bene l'XML per cercare altri possibili problemi) ... è una libreria JS comune/standard per fare questo per me makeSafeForXML (inString)? – Seth

+0

Inoltre, non si finirebbe probabilmente per doppia entitizing per caso? Ad esempio, se in un browser futuro XMLSerializer() + attr() finisce con l'abilitazione, finirai con il doppio escape? – Seth

risposta

10

Ecco una funzione sanitizeStringForXML(), che può essere usato per pulire le stringhe prima assegnazione, o una funzione derivata removeInvalidCharacters (XmlNode) che può essere trasmesso un albero DOM e sarà automaticamente disinfettare attributi e textNodes così sono sicuri da conservare.

var stringWithSTX = "Bad" + String.fromCharCode(2) + "News"; 
var xmlNode = $("<myelem/>").attr("badattr", stringWithSTX); 

var serializer = new XMLSerializer(); 
var invalidXML = serializer.serializeToString(xmlNode); 

// Now cleanse it: 
removeInvalidCharacters(xmlNode); 
var validXML = serializer.serializeToString(xmlNode); 

ho basato questo su un elenco di caratteri dal non-restricted characters section of this wikipedia article, ma gli aerei supplementari richiedono caratteri Unicode 5-hex-cifre, e la regex Javascript non include una sintassi per questo, quindi per ora, I' m appena li si esclude (non vi manca troppo ...):

// WARNING: too painful to include supplementary planes, these characters (0x10000 and higher) 
// will be stripped by this function. See what you are missing (heiroglyphics, emoji, etc) at: 
// http://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Multilingual_Plane 
var NOT_SAFE_IN_XML_1_0 = /[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm; 
function sanitizeStringForXML(theString) { 
    "use strict"; 
    return theString.replace(NOT_SAFE_IN_XML_1_0, ''); 
} 

function removeInvalidCharacters(node) { 
    "use strict"; 

    if (node.attributes) { 
     for (var i = 0; i < node.attributes.length; i++) { 
      var attribute = node.attributes[i]; 
      if (attribute.nodeValue) { 
       attribute.nodeValue = sanitizeStringForXML(attribute.nodeValue); 
      } 
     } 
    } 
    if (node.childNodes) { 
     for (var i = 0; i < node.childNodes.length; i++) { 
      var childNode = node.childNodes[i]; 
      if (childNode.nodeType == 1 /* ELEMENT_NODE */) { 
       removeInvalidCharacters(childNode); 
      } else if (childNode.nodeType == 3 /* TEXT_NODE */) { 
       if (childNode.nodeValue) { 
        childNode.nodeValue = sanitizeStringForXML(childNode.nodeValue); 
       } 
      } 
     } 
    } 
} 

si noti che questo rimuove solo i caratteri non validi da nodeValues ​​di attributi e textNodes. Non controlla i nomi dei tag oi nomi degli attributi, i commenti, ecc.

+0

apprezzate le correzioni alla lista dei caratteri, se ci sono errori, non saprei :-( – Seth

+0

risolvere il mio problema dopo 5 ore di ricerca, grazie – MOB

Problemi correlati