Cómo evitar que XMLReader deshaga los caracteres

Me gustaría crear un lector XML simple que lea un nodo completo (incluidos los subnodos) como texto:

string TXML = @"<xml><text>hall&#xF6;le</text></xml>";

XmlReader r = XmlReader.Create(new StringReader(TXML));
r.Read(); r.Read();

string o = r.ReadOuterXml();

ReadOuterXml hace el trabajo pero no escapa a los signos ya escapados:

"<text>hallöle</text>"

Deseo tener el resultado:

"<text>hall&#xF6;le</text>"

¿Cómo puedo omitir ese 'sin escape'? Quiero almacenar estos fragmentos en una base de datos y necesito ese escape. Además, no quiero analizar y recrear los fragmentos.

preguntado el 22 de mayo de 12 a las 15:05

¿Puede modificar la fuente XML para escapar de la & símbolo con &amp;? -

Cuando inserta los datos en la base de datos, creo que querrá que sean los datos correctos, no los datos escapados. De esa manera, puede buscarlo y cuando lea los datos de la base de datos, será correcto. No debería necesitar escapar de los datos cuando los está insertando en la base de datos si está usando ADO y parámetros. -

Soy el hombre en el medio. No puedo alterar la fuente. Además, si devuelvo los datos almacenados al cliente, espera que se escape nuevamente. Es por eso que me gustaría dejarlo como está. -

4 Respuestas

Tuve un problema similar, quería mantener los caracteres escapados al leer de xml, pero en muchos casos, al llamar a ReadOuterXml(), solo se mantuvieron algunos de los caracteres y al menos se transformó oane (encabezado " en lugar de ")

Mi solución fue la siguiente:

string TXML = @"<xml><text>hall&#xF6;le</text></xml>";
TXML = TXML.Replace("&", "&amp;");
XmlTextReader r = new XmlTextReader(new StringReader(TXML));
r.Read(); r.Read();
// now we are at the text element
r.ReadStartElement()
var content = SecurityElement.Escape(r.ReadContentAsString())
r.ReadEndElement()

respondido 14 nov., 12:13

Encontré dos soluciones. Ambos no son muy agradables, pero tal vez puedas decirme cuál tiene menos inconvenientes.

Ambas soluciones se basan en el uso directo de 'XmlTextReader' en lugar de 'XmlReader'. Viene con la propiedad 'LinePosition' que me lleva a la primera solución y con el método 'ReadChars' como base para la segunda.

Solución (1), obtenga datos de la cadena original a través de índices

Problemas:

  • no funciona en entradas de flujo
  • no funciona si xml tiene varias líneas

Código

string TXML = @"<xml><data></data><rawnode at=""10 4""><text>hall&#xF6;le</text><z d=""2"">3</z></rawnode><data></data></xml>";

//XmlReader r = XmlReader.Create(new StringReader(TXML));
XmlTextReader r = new XmlTextReader(new StringReader(TXML));

// read to node which shall be retrived "raw"
while ( r.Read() )
{
    if ( r.Name.Equals("rawnode") )
        break;
}

// here we start
int Begin = r.LinePosition;
r.Skip();
int End = r.LinePosition;

// get it out
string output=TXML.Substring(Begin - 2, End - Begin);

Solución (2), obtener datos con 'ReadChars'

Problemas:

  • Tengo que analizar y recrear el marcado 'externo' de mi etiqueta que me gustaría leer.
  • Esto podría costar rendimiento.
  • Podría introducir errores.

Código:

// ... again create XmlTextReader and read to rawnode, then:
// here we start
int buflen = 15;
char[] buf = new char[buflen];
StringBuilder sb= new StringBuilder("<",20);

//get start tag and attributes    
string tagname=r.Name;
sb.Append(tagname);
bool hasAttributes = r.MoveToFirstAttribute();
while (hasAttributes)
{
    sb.Append(" " + r.Name + @"=""" + r.Value + @"""");
    hasAttributes = r.MoveToNextAttribute();
}
sb.Append(@">");
r.MoveToContent();

//get raw inner data    
int cnt;
while ((cnt = r.ReadChars(buf, 0, buflen)) > 0)
{
    if ( cnt<buflen )
        buf[cnt]=(char)0;
    sb.Append(buf);
}

//append end tag    
sb.Append("</" + tagname + ">");

// get it out
string output = sb.ToString();

contestado el 23 de mayo de 12 a las 15:05

Eche un vistazo a su encabezado xml y verifique que contenga algo como esto: <?xml version="1.0" encoding="ISO-8859-9"?>

Para escapar y no escapar, puede usar las funciones c # InnerXml y InnerText :

public static string XmlEscape(string unescaped)
{
    XmlDocument doc = new XmlDocument();
    var node = doc.CreateElement("root");
    node.InnerText = unescaped;
    return node.InnerXml;
}

public static string XmlUnescape(string escaped)
{
    XmlDocument doc = new XmlDocument();
    var node = doc.CreateElement("root");
    node.InnerXml = escaped;
    return node.InnerText;
}

contestado el 22 de mayo de 12 a las 15:05

´cadena TXML = @" Hallöle ";´ pero analizar esa cadena con el mismo código no cambió el resultado. - user1410404

Además, gracias por sus métodos Xml (un) Escape, pero usarlos significaría leer y recrear todo el XML interno. Eso es exactamente lo que trato de omitir. - user1410404

Entiendo su deseo de no tener que analizar y recrear los caracteres escapados, pero no puedo encontrar una manera de no hacerlo a menos que lo personalice por completo. ¿Quizás esto no es tan malo?

string TXML = @"<xml><text>hall&#xF6;le</text></xml>";
TXML = TXML.Replace("&", "&amp;");
XmlTextReader r = new XmlTextReader(new StringReader(TXML));
r.Read(); r.Read();

string o = r.ReadOuterXml();
o = o.Replace("&amp;", "&");

contestado el 22 de mayo de 12 a las 16:05

Sí, tal vez esta es la única manera. Gracias por eso. Pero además de tener una solución muy aproximada, podría ser visible en el rendimiento de la aplicación. Leí los fragmentos de un gran XML y tendría que leer y escribir la fuente varias veces. - user1410404

la misma fuente? Simplemente léalo una vez y guárdelo en una variable que luego puede usar para escribir tantas veces como necesite. - BuscadorDeConocimiento

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.