net - xmldocument c# ejemplo
La sangrĂa XML al inyectar una cadena XML en un XmlWriter (6)
Tengo un XmlTextWriter escribiendo en un archivo y un XmlWriter usando ese escritor de texto. Este escritor de texto está configurado para generar XML con sangría de tabulación:
XmlTextWriter xtw = new XmlTextWriter("foo.xml", Encoding.UTF8);
xtw.Formatting = Formatting.Indented;
xtw.IndentChar = ''/t'';
xtw.Indentation = 1;
XmlWriter xw = XmlWriter.Create(xtw);
Cambiado por el enlace de MSDN de Jeff:
XmlWriterSettings set = new XmlWriterSettings();
set.Indent = true;
set.IndentChars = "/t";
set.Encoding = Encoding.UTF8;
xw = XmlWriter.Create(f, set);
Esto no cambia el resultado final.
Ahora tengo una profundidad arbitraria en mi XmlWriter y obtengo una cadena de XML de otro lugar (que no puedo controlar) que es un XML de una sola línea, sin sangría. Si llamo xw.WriteRaw (), esa cadena se inyecta literalmente y no sigue la sangría que quiero.
...
string xml = ExternalMethod();
xw.WriteRaw(xml);
...
Esencialmente, quiero un WriteRaw que analice la cadena XML y pase por todo el WriteStartElement, etc. para que se reformatee según la configuración de XmlTextWriter''s.
Mi preferencia es una forma de hacer esto con la configuración que ya tengo y hacerlo sin tener que volver a cargar el XML final solo para reformatearlo. También preferiría no analizar la cadena XML con los gustos de XmlReader y luego imitar lo que encuentra en mi XmlWriter (proceso muy manual).
Al final de esto, prefiero tener una solución simple que una que siga mis preferencias. (Naturalmente, la mejor solución sería simple y sigue mis preferencias).
¿Qué hay de usar un XmlReader para leer el xml como nodos xml?
string xml = ExternalMethod();
XmlReader reader = XmlReader.Create(new StringReader(xml));
xw.WriteNode(reader, true);
Estaba buscando una respuesta a este problema pero en VB.net.
Gracias a Colin Burnett, lo resolví. Hice dos correcciones: primero, XmlReader
debe ignorar los espacios en blanco ( settings.IgnoreWhiteSpaces
); En segundo lugar, el lector debe volver al elemento después de leer los atributos. A continuación puedes ver cómo se ve el código.
También probé la solución de GreyCloud, pero en el XML generado había algunos atributos de vacíos molestos (xlmns).
Private Sub PipeXMLIntoWriter(xw As XmlWriter, xml As String)
Dim dat As Byte() = New System.Text.UTF8Encoding().GetBytes(xml)
Dim m As New MemoryStream()
m.Write(dat, 0, dat.Length)
m.Seek(0, SeekOrigin.Begin)
Dim settings As New XmlReaderSettings
settings.IgnoreWhitespace = True
settings.IgnoreComments = True
Dim r As XmlReader = XmlReader.Create(m, settings)
While r.Read()
Select Case r.NodeType
Case XmlNodeType.Element
xw.WriteStartElement(r.Name)
If r.HasAttributes Then
For i As Integer = 0 To r.AttributeCount - 1
r.MoveToAttribute(i)
xw.WriteAttributeString(r.Name, r.Value)
Next
r.MoveToElement()
End If
If r.IsEmptyElement Then
xw.WriteEndElement()
End If
Exit Select
Case XmlNodeType.EndElement
xw.WriteEndElement()
Exit Select
Case XmlNodeType.Text
xw.WriteString(r.Value)
Exit Select
Case Else
Throw New Exception("Unrecognized node type: " + r.NodeType)
End Select
End While
End Sub
Esto es lo mejor que tengo hasta ahora. Un proceso muy manual que solo soporta lo que está escrito. Mi cadena XML no es más que etiquetas, atributos y datos de texto. Si admitiera espacios de nombres, CDATA, etc., entonces esto tendría que crecer en consecuencia.
Muy manual, muy desordenado y muy propenso a los errores, pero cumple con mis preferencias.
private static void PipeXMLIntoWriter(XmlWriter xw, string xml)
{
byte[] dat = new System.Text.UTF8Encoding().GetBytes(xml);
MemoryStream m = new MemoryStream();
m.Write(dat, 0, dat.Length);
m.Seek(0, SeekOrigin.Begin);
XmlReader r = XmlReader.Create(m);
while (r.Read())
{
switch (r.NodeType)
{
case XmlNodeType.Element:
xw.WriteStartElement(r.Name);
if (r.HasAttributes)
{
for (int i = 0; i < r.AttributeCount; i++)
{
r.MoveToAttribute(i);
xw.WriteAttributeString(r.Name, r.Value);
}
}
if (r.IsEmptyElement)
{
xw.WriteEndElement();
}
break;
case XmlNodeType.EndElement:
xw.WriteEndElement();
break;
case XmlNodeType.Text:
xw.WriteString(r.Value);
break;
default:
throw new Exception("Unrecognized node type: " + r.NodeType);
}
}
}
No debe usar XmlTextWriter
, como se indica en MSDN donde dice:
En la versión 2.0 de .NET Framework, la práctica recomendada es crear instancias de XmlWriter usando el método XmlWriter.Create y la clase XmlWriterSettings. Esto le permite aprovechar al máximo todas las nuevas características introducidas en esta versión. Para obtener más información, consulte Crear escritores XML.
En su lugar, debes usar XmlWriter.Create para obtener tu escritor. Luego puedes usar la clase XmlWriterSettings
para especificar cosas como la sangría.
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = "/t";
Actualizar
Creo que puedes usar WriteNode. Toma su cadena xml y la carga en un XDocument o XmlReader y luego usa el nodo para escribirla en su XmlWriter.
Qué tal si:
string xml = ExternalMethod();
var xd = XDocument.Parse(xml);
xd.WriteTo(xw);
componiendo las respuestas anteriores he encontrado este trabajo:
private static string FormatXML(string unformattedXml) {
// first read the xml ignoring whitespace
XmlReaderSettings readeroptions= new XmlReaderSettings {IgnoreWhitespace = true};
XmlReader reader = XmlReader.Create(new StringReader(unformattedXml),readeroptions);
// then write it out with indentation
StringBuilder sb = new StringBuilder();
XmlWriterSettings xmlSettingsWithIndentation = new XmlWriterSettings { Indent = true};
using (XmlWriter writer = XmlWriter.Create(sb, xmlSettingsWithIndentation)) {
writer.WriteNode(reader, true);
}
return sb.ToString();
}