I'm reading an svg/xml with XmlTextReader
and I want to write just some of its elements back in a new svg/xml file
<svg>
<rect x="135.7" y="537.4" fill="none" stroke="#000000" stroke-width="0.2894" width="36.6" height="42.2"/>
<rect x="99" y="537.4" fill="#A0C9EC" stroke="#000000" stroke-width="0.2894" width="36.7" height="42.2"/>
</svg>
I want the rect elements that are filled with "none" so I started reading and writing
var reader = new XmlTextReader(file.InputStream);
var writer = new XmlTextWriter(svgPath + fileNameWithoutExtension + "-less" + extension, null);
writer.WriteStartDocument();
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "svg")
{
writer.WriteStartElement(reader.Name);
while(reader.MoveToNextAttribute()){
writer.WriteAttributes(reader, true);
}
}
if (reader.Name == "rect" || reader.Name == "polygon")
{
while(reader.MoveToNextAttribute()){
if(reader.Name == "fill" && reader.value == "none"){
writer.WriteStartElement(reader.Name);
writer.WriteAttributes(reader, true);
writer.WriteEndElement();
}
}
}
break;
case XmlNodeType.EndElement:
break;
default:
break;
}
}
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Close();
but that returns a file with "fill" elements and no "x" and "y" attributes (because the WriteAttributes
read from the current position and the reader is in the fill attribute)
<svg>
<fill="none" stroke="#000000" stroke-width="0.2894" width="36.6" height="42.2"/>
</svg>
Is there a way to get the result I want? I don't want to use XmlDocument
since my svg files are large and take a long time to load with XmlDoc.Load
Thanks
Try the following; you can adapt to suit:
if (reader.Name == "rect" || reader.Name == "polygon")
{
string fill = reader.GetAttribute("fill"); //Read ahead for the value of the fill attr
if(String.Compare(fill, "none", StringComparison.InvariantCultureIgnoreCase) == 0) //if the value is what we expect then just wholesale copy this node.
{
writer.WriteStartElement(reader.Name);
writer.WriteAttributes(reader, true);
writer.WriteEndElement();
}
}
Note that GetAttribute does not move the reader, allowing you to stay in the context of the rect or polygon node.
You could probably also try revising your first attempt with a single reader.MoveToFirstAttribute() - I haven't tested that but it should move you back to the first element of the current node.
You might also want to investigate the XPathDocument class - this is a lot lighter than XmlDocument but you still load the entire structure into memory first so may not be suitable - selecting the nodes you want would then simply be a case of using the XPath:
//rect[@fill='none'] || //polygon[@fill='none']
Finally, you could also use an XSLT. If you wanted to post a more complete structure for your source document I'd be happy to write one for you.