使用C#与XPath向SVG插入元素时SelectSingleNode返回null的问题
使用C#和XPath向SVG插入circle元素时出现null引用问题
问题场景
需要向SVG文件末尾插入一个circle元素,修改前后内容如下:
修改前的SVG
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="594.75pt" height="841.5pt" viewBox="0 0 594.75 841.5" style="border: 1px solid red"> <circle cx="50%" cy="50%" r="50" fill="red" /> </svg>
期望修改后的SVG
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="594.75pt" height="841.5pt" viewBox="0 0 594.75 841.5" style="border: 1px solid red"> <circle cx="50%" cy="50%" r="50" fill="red" /> <circle stroke="blue" stroke-width="3" cx="148.63pt" cy="401.02pt" r="84.15" fill-opacity="0.1"/> </svg>
编写的C#代码执行后mapElement为null,无法完成插入:
XmlDocument doc = new XmlDocument(); doc.Load(@"D:\\test.svg"); XmlNamespaceManager xmlnsManager = new XmlNamespaceManager(doc.NameTable); xmlnsManager.AddNamespace("xlink", "http://www.w3.org/1999/xlink"); xmlnsManager.AddNamespace("svg", "http://www.w3.org/2000/svg"); XmlDocumentFragment xmlDocFrag = doc.CreateDocumentFragment(); xmlDocFrag.InnerXml = @"<circle stroke=\"blue\" stroke-width=\"3\" cx=\"148.63pt\" cy=\"401.02pt\" r=\"84.15\" fill-opacity=\"0.1\"/>"; XmlElement mapElement = (XmlElement)doc.SelectSingleNode(@"//svg[last()]", xmlnsManager); mapElement.AppendChild(xmlDocFrag); // <----- null !! doc.Save(path);
解决方案
1. 修正XPath选择器
SVG根元素属于http://www.w3.org/2000/svg命名空间,XPath必须使用已注册的命名空间前缀svg:来匹配元素,原代码的//svg[last()]无法找到目标元素,应改为:
XmlElement mapElement = (XmlElement)doc.SelectSingleNode(@"//svg:svg[last()]", xmlnsManager);
2. 确保新元素带SVG命名空间
直接用XmlDocumentFragment.InnerXml创建的circle元素不会继承SVG命名空间,导致插入后元素不在正确的命名空间下,建议直接创建带命名空间的元素:
// 创建带SVG命名空间的circle元素 XmlElement newCircle = doc.CreateElement("circle", "http://www.w3.org/2000/svg"); newCircle.SetAttribute("stroke", "blue"); newCircle.SetAttribute("stroke-width", "3"); newCircle.SetAttribute("cx", "148.63pt"); newCircle.SetAttribute("cy", "401.02pt"); newCircle.SetAttribute("r", "84.15"); newCircle.SetAttribute("fill-opacity", "0.1");
完整修正后的代码
XmlDocument doc = new XmlDocument(); string path = @"D:\\test.svg"; doc.Load(path); XmlNamespaceManager xmlnsManager = new XmlNamespaceManager(doc.NameTable); xmlnsManager.AddNamespace("svg", "http://www.w3.org/2000/svg"); // 获取SVG根元素 XmlElement svgRoot = (XmlElement)doc.SelectSingleNode(@"//svg:svg[last()]", xmlnsManager); // 创建带命名空间的新circle元素 XmlElement newCircle = doc.CreateElement("circle", "http://www.w3.org/2000/svg"); newCircle.SetAttribute("stroke", "blue"); newCircle.SetAttribute("stroke-width", "3"); newCircle.SetAttribute("cx", "148.63pt"); newCircle.SetAttribute("cy", "401.02pt"); newCircle.SetAttribute("r", "84.15"); newCircle.SetAttribute("fill-opacity", "0.1"); // 插入到SVG根元素末尾 svgRoot.AppendChild(newCircle); doc.Save(path);
补充说明
如果坚持使用XmlDocumentFragment,需要在InnerXml中明确指定命名空间前缀:
xmlDocFrag.InnerXml = @"<svg:circle stroke=""blue"" stroke-width=""3"" cx=""148.63pt"" cy=""401.02pt"" r=""84.15"" fill-opacity=""0.1"" xmlns:svg=""http://www.w3.org/2000/svg""/>";
内容的提问来源于stack exchange,提问作者anon
相关产品推荐
相关产品推荐

