Taking inspiration from this blog post, you can basically just stream the contents of the XmlReader
straight to the XmlWriter
similarly to your example code, but handling all node types. Using WriteNode
, as in your example code, will add the node and all child nodes, so you wouldn't be able to handle each descendant in your source XML.
In addition, you need to make sure you read to the end of the element you want to skip - ReadSubtree
creates an XmlReader
for this, but it doesn't actually do any reading. You need to ensure this is read to the end.
The resulting code might look like this:
using (var reader = XmlReader.Create(new StringReader(xml), rs))
using (var writer = XmlWriter.Create(Console.Out, ws))
{
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
var subTreeReader = reader.ReadSubtree();
if (HandleElement(reader, writer))
{
ReadToEnd(subTreeReader);
}
else
{
writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
writer.WriteAttributes(reader, true);
if (reader.IsEmptyElement)
{
writer.WriteEndElement();
}
}
break;
case XmlNodeType.Text:
writer.WriteString(reader.Value);
break;
case XmlNodeType.Whitespace:
case XmlNodeType.SignificantWhitespace:
writer.WriteWhitespace(reader.Value);
break;
case XmlNodeType.CDATA:
writer.WriteCData(reader.Value);
break;
case XmlNodeType.EntityReference:
writer.WriteEntityRef(reader.Name);
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
writer.WriteProcessingInstruction(reader.Name, reader.Value);
break;
case XmlNodeType.DocumentType:
writer.WriteDocType(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value);
break;
case XmlNodeType.Comment:
writer.WriteComment(reader.Value);
break;
case XmlNodeType.EndElement:
writer.WriteFullEndElement();
break;
}
}
}
private static void ReadToEnd(XmlReader reader)
{
while (!reader.EOF)
{
reader.Read();
}
}
Obviously put whatever your logic is inside HandleElement
, returning true
if the element is handled (and therefore to be ignored). The implementation for the logic in your example code would be:
private static bool HandleElement(XmlReader reader, XmlWriter writer)
{
if (reader.Name == "e")
{
writer.WriteElementString("element", "val1");
return true;
}
return false;
}
Here is a working demo: https://dotnetfiddle.net/FFIBU4