我重写了一个传入XmlReader的方法,我需要找到一个特定的元素,添加一个属性,然后创建一个新的XmlReader,或者用修改后的内容替换现有的XmlReader。我正在使用C#4.0
我已经使用XElement(Linq)进行了调查,但我似乎无法操纵现有元素并添加属性和值。
我知道XmlWriter有WriteAttributeString这很棒但是我不确定它们是如何组合起来的
我希望能够做到这样的事情---这是伪代码!
public XmlReader DoSomethingWonderful(XmlReader reader)
{
Element element = reader.GetElement("Test");
element.SetAttribute("TestAttribute","This is a test");
reader.UpdateElement(element);
return reader;
}
答案 0 :(得分:13)
XmlReader / Writer是顺序访问流。您必须在一端读入,按照您想要的方式处理流,并将其写出另一端。优点是您不需要将整个内容读入内存并构建DOM,这是您使用任何基于XmlDocument的方法所获得的。
这个方法应该让你入门:
private static void PostProcess(Stream inStream, Stream outStream)
{
var settings = new XmlWriterSettings() { Indent = true, IndentChars = " " };
using (var reader = XmlReader.Create(inStream))
using (var writer = XmlWriter.Create(outStream, settings)) {
while (reader.Read()) {
switch (reader.NodeType) {
case XmlNodeType.Element:
writer.WriteStartElement(reader.Prefix, reader.Name, reader.NamespaceURI);
writer.WriteAttributes(reader, true);
//
// check if this is the node you want, inject attributes here.
//
if (reader.IsEmptyElement) {
writer.WriteEndElement();
}
break;
case XmlNodeType.Text:
writer.WriteString(reader.Value);
break;
case XmlNodeType.EndElement:
writer.WriteFullEndElement();
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
writer.WriteProcessingInstruction(reader.Name, reader.Value);
break;
case XmlNodeType.SignificantWhitespace:
writer.WriteWhitespace(reader.Value);
break;
}
}
}
}
这不像派生自己的XmlWriter那么干净,但我发现它更容易。
<强> [编辑] 强>
如何一次打开两个流的示例可能是这样的:
using (FileStream readStream = new FileStream(@"c:\myFile.xml", FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write)) {
using (FileStream writeStream = new FileStream(@"c:\myFile.xml", FileMode.OpenOrCreate, FileAccess.Write)) {
PostProcess(readStream, writeStream);
}
}
答案 1 :(得分:1)
使用XmlReader
无法轻松完成此操作 - 至少,不是没有从阅读器中读取整个XML文档,而是使用它,然后从结果中创建新的XmlReader
。这虽然击败了使用XmlReader
的许多要点 - 即流式传输大型文档的能力。
你可以潜在地从XmlReader
派生,将大多数方法调用转发到现有的阅读器,但在适当的时候拦截它们以添加额外的属性等......但我怀疑代码是真的非常复杂和脆弱。
答案 2 :(得分:1)
我使用以下胶带编码
修复了它 public XmlReader FixUpReader(XmlReader reader)
{
reader.MoveToContent();
string xml = reader.ReadOuterXml();
string dslVersion = GetDSLVersion();
string Id = GetID();
string processedValue = string.Format("<ExampleElement dslVersion=\"{1}\" Id=\"{2}\" ", dslVersion, Id);
xml = xml.Replace("<ExampleElement ", processedValue);
MemoryStream ms = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(xml));
XmlReaderSettings settings = new XmlReaderSettings();
XmlReader myReader = XmlReader.Create(ms);
myReader.MoveToContent();
return myReader;
}
我觉得这样做很脏,但它正在工作......
答案 3 :(得分:0)
我更愿意将xml加载到XmlDocument
对象中并使用Attributes
集合来修改值并调用Save
方法来更新此值。下面的代码适用于我。
public static void WriteElementValue ( string sName, string element, string value)
{
try
{
var node = String.Format("//elements/element[@name='{0}']", sName);
var doc = new XmlDocument { PreserveWhitespace = true };
doc.Load(configurationFileName);
var nodeObject = doc.SelectSingleNode(node);
if (nodeObject == null)
throw new XmlException(String.Format("{0} path does not found any matching
node", node));
var elementObject = nodeObject[element];
if (elementObject != null)
{
elementObject.Attributes["value"].Value = value;
}
doc.Save(configurationFileName);
}
catch (Exception ex)
{
throw new ExitLevelException(ex, false);
}
}
我也观察到当你使用XmlWriter或XmlSerializer时,空格没有被正确保存,这有时会很烦人
答案 4 :(得分:-2)
string newvalue = "10";
string presentvalue = "";
string newstr = "";
XmlReader xmlr = XmlReader.Create(new StringReader(str));
while (xmlr.Read())
{
if (xmlr.NodeType == XmlNodeType.Element)
{
if (xmlr.Name == "priority")
{
presentvalue = xmlr.ReadElementContentAsString();
newstr = str.Replace(presentvalue, newvalue);
}
}
}
// newstr可以写回文件...即编辑的xml