如何根据某个属性选择一个xml元素,并将其写回另一个文件中

时间:2012-01-17 22:14:07

标签: c# xml xmlreader xmlwriter

我正在阅读带有XmlTextReader的svg / xml,我想在新的svg / xml文件中写回一些元素

<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>

我想要填充“none”的rect元素,所以我开始阅读和写作

 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();

但是返回一个带有“fill”元素且没有“x”和“y”属性的文件(因为WriteAttributes从当前位置读取而读者位于fill属性中)

 <svg>
     <fill="none" stroke="#000000" stroke-width="0.2894" width="36.6" height="42.2"/>
 </svg>

有没有办法得到我想要的结果?我不想使用XmlDocument,因为我的svg文件很大,需要很长时间来加载XmlDoc.Load

由于

3 个答案:

答案 0 :(得分:3)

尝试以下方法;你可以适应:

     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(); 
            } 
        } 

请注意,GetAttribute不会移动阅读器,使您可以保留在rect或polygon节点的上下文中。

您也可以尝试使用单个reader修改您的第一次尝试.MoveToFirstAttribute() - 我没有测试过,但它应该让您回到当前节点的第一个元素。

您可能还想调查XPathDocument类 - 这比XmlDocument轻很多但是您仍然首先将整个结构加载到内存中,因此可能不合适 - 选择您想要的节点然后只是使用的XPath:

//rect[@fill='none'] || //polygon[@fill='none'] 

最后,您还可以使用XSLT。如果您想为源文档发布更完整的结构,我很乐意为您编写一个。

答案 1 :(得分:2)

这是使用命令式C#的讨厌的业务,您可以考虑使用XSLT: http://www.w3schools.com/xsl/el_value-of.asp

答案 2 :(得分:2)

在调用MoveToNextAttribute之前,需要将reader.Name存储在变量中。然后,当您调用WriteStartElement时,请改用该值。

if (reader.Name == "rect" || reader.Name == "polygon")
{
    // get tag name here
    var tagName = reader.Name;

    while(reader.MoveToNextAttribute()){
        if(reader.Name == "fill" && reader.value == "none"){

            // write tag name here
            writer.WriteStartElement(tagName);

            writer.WriteAttributes(reader, true);
            writer.WriteEndElement();
        }
    }
}