是否可以使用 xmlreader 更改节点值?
is it possible to alter the node value with xmlreader?
我正在读取大约 100mb 的 XML 流,我想替换 超过 1mb 的值。
示例输入
<root>
<visit>yes</visit>
<filedata>SDFSFDSDFfgdfgsgdf==(this is 5 mb)</filedata>
<type>pdf</type>
<moredata>sssssssssssssss (this 2mb)</moredata>
</root>
预期输出
<root>
<visit>yes</visit>
<filedata>REPLACED TEXT</filedata>
<type>pdf</type>
<moredata>REPLACED TEXT</moredata>
</root>
这是我用来读取流以及检查大小的方法:
XmlReader rdr = XmlReader.Create (new System.IO.StringReader (xml));
while (rdr.Read ()) {
if (rdr?.Value.Length > ONEMEGABYTE) {
//replace value with "REPLACE TEXT"}
}
如何替换 rdr.Value
中的值?
这里有一个使用 Xml Reader 和 Xml Linq
替换的例子
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication29
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
while (!reader.EOF)
{
if (reader.Name != "visits")
{
reader.ReadToFollowing("visits");
}
if (!reader.EOF)
{
XElement visits = (XElement)XElement.ReadFrom(reader);
XElement filedata = visits.Element("filedata");
filedata.SetValue("New Data");
}
}
}
}
}
这是xml我用的
<root>
<visits>
<visit>yes</visit>
<filedata>REPLACED TEXT</filedata>
<type>pdf</type>
<moredata>REPLACED TEXT</moredata>
</visits>
</root>
我们可以使用 XmlDocument 来实现。获取根节点的所有子节点,然后循环遍历所有节点 -
XmlDocument Doc = new XmlDocument();
Doc.Load(@"yourpath.xml");
XmlNodeList xmlNodelist = Doc.DocumentElement.ChildNodes;
foreach (XmlNode node in xmlNodelist)
{
if(node.InnerText.Length > ONEMEGABYTE)
{
node.InnerText = "new value";
}
}
Doc.Save(@"yourpath.xml"); //will replace new changes in the source file.
您可以从 class XmlReader
到 "filter" 不想要的元素,然后将 XmlDocument.Load()
与您的 reader 一起使用,而不是让它创建自己的元素。
请注意,这将仅排除违规标签的 值 :如果您在 Read() 循环中放置一个断点,您会发现 <foo>bar</foo>
分为三部分:<foo>
具有没有值的 NodeType 元素,"bar" 具有具有空 LocalName 的 NodeType 文本,</foo>
是没有值的 NodeType EndElement。如果"bar"超过限制长度,下面的"filter"会将<foo>bar</foo>
变成<foo></foo>
,根据[=38=的长度排除所有<foo>bar</foo>
],你必须向前看。可行,但也许不值得你花时间。希望这不是这里的要求。
这个 class 的一个替代(或补充)可能是一个带有 Func<string, string>
的版本,每个 Value
通过:s => (s.Length > MAX_LEN) ? "" : s
。
此外,据我所知,XmlTextReaderImpl
(_reader
的实际类型)可能会缓存整个文本并降低性能。您可能还必须为这件事编写自己的胆量。
public class FilteredXmlReader : XmlReader
{
public Func<XmlReader, bool> Filter;
private XmlReader _reader;
private FilteredXmlReader(TextReader input, Func<XmlReader, bool> filterProc)
{
Filter = filterProc;
_reader = XmlReader.Create(input);
}
public static new XmlReader Create(TextReader input, Func<XmlReader, bool> filterProc)
{
return new FilteredXmlReader(input, filterProc);
}
public override bool Read()
{
var b = _reader.Read();
while (!(bool)Filter?.Invoke(_reader))
{
b = _reader.Read();
}
return b;
}
#region Wrapper Boilerplate
public override XmlNodeType NodeType => _reader.NodeType;
public override string LocalName => _reader.LocalName;
public override string NamespaceURI => _reader.NamespaceURI;
public override string Prefix => _reader.Prefix;
public override string Value => _reader.Value;
public override int Depth => _reader.Depth;
public override string BaseURI => _reader.BaseURI;
public override bool IsEmptyElement => _reader.IsEmptyElement;
public override int AttributeCount => _reader.AttributeCount;
public override bool EOF => _reader.EOF;
public override ReadState ReadState => _reader.ReadState;
public override XmlNameTable NameTable => _reader.NameTable;
public override string GetAttribute(string name) => _reader.GetAttribute(name);
public override string GetAttribute(string name, string namespaceURI) => _reader.GetAttribute(name, namespaceURI);
public override string GetAttribute(int i) => _reader.GetAttribute(i);
public override string LookupNamespace(string prefix) => _reader.LookupNamespace(prefix);
public override bool MoveToAttribute(string name) => _reader.MoveToAttribute(name);
public override bool MoveToAttribute(string name, string ns) => _reader.MoveToAttribute(name, ns);
public override bool MoveToElement() => _reader.MoveToElement();
public override bool MoveToFirstAttribute() => _reader.MoveToFirstAttribute();
public override bool MoveToNextAttribute() => _reader.MoveToNextAttribute();
public override bool ReadAttributeValue() => _reader.ReadAttributeValue();
public override void ResolveEntity() => _reader.ResolveEntity();
#endregion Wrapper Boilerplate
}
用法:
var xml = "<test />";
XmlDocument doc = new XmlDocument();
XmlReader rdr = FilteredXmlReader.Create(new System.IO.StringReader(xml),
r => r?.Value.Length < 20);
var filteredXML = doc.OuterXml;
我正在读取大约 100mb 的 XML 流,我想替换 超过 1mb 的值。
示例输入
<root>
<visit>yes</visit>
<filedata>SDFSFDSDFfgdfgsgdf==(this is 5 mb)</filedata>
<type>pdf</type>
<moredata>sssssssssssssss (this 2mb)</moredata>
</root>
预期输出
<root>
<visit>yes</visit>
<filedata>REPLACED TEXT</filedata>
<type>pdf</type>
<moredata>REPLACED TEXT</moredata>
</root>
这是我用来读取流以及检查大小的方法:
XmlReader rdr = XmlReader.Create (new System.IO.StringReader (xml));
while (rdr.Read ()) {
if (rdr?.Value.Length > ONEMEGABYTE) {
//replace value with "REPLACE TEXT"}
}
如何替换 rdr.Value
中的值?
这里有一个使用 Xml Reader 和 Xml Linq
替换的例子using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication29
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
while (!reader.EOF)
{
if (reader.Name != "visits")
{
reader.ReadToFollowing("visits");
}
if (!reader.EOF)
{
XElement visits = (XElement)XElement.ReadFrom(reader);
XElement filedata = visits.Element("filedata");
filedata.SetValue("New Data");
}
}
}
}
}
这是xml我用的
<root>
<visits>
<visit>yes</visit>
<filedata>REPLACED TEXT</filedata>
<type>pdf</type>
<moredata>REPLACED TEXT</moredata>
</visits>
</root>
我们可以使用 XmlDocument 来实现。获取根节点的所有子节点,然后循环遍历所有节点 -
XmlDocument Doc = new XmlDocument();
Doc.Load(@"yourpath.xml");
XmlNodeList xmlNodelist = Doc.DocumentElement.ChildNodes;
foreach (XmlNode node in xmlNodelist)
{
if(node.InnerText.Length > ONEMEGABYTE)
{
node.InnerText = "new value";
}
}
Doc.Save(@"yourpath.xml"); //will replace new changes in the source file.
您可以从 class XmlReader
到 "filter" 不想要的元素,然后将 XmlDocument.Load()
与您的 reader 一起使用,而不是让它创建自己的元素。
请注意,这将仅排除违规标签的 值 :如果您在 Read() 循环中放置一个断点,您会发现 <foo>bar</foo>
分为三部分:<foo>
具有没有值的 NodeType 元素,"bar" 具有具有空 LocalName 的 NodeType 文本,</foo>
是没有值的 NodeType EndElement。如果"bar"超过限制长度,下面的"filter"会将<foo>bar</foo>
变成<foo></foo>
,根据[=38=的长度排除所有<foo>bar</foo>
],你必须向前看。可行,但也许不值得你花时间。希望这不是这里的要求。
这个 class 的一个替代(或补充)可能是一个带有 Func<string, string>
的版本,每个 Value
通过:s => (s.Length > MAX_LEN) ? "" : s
。
此外,据我所知,XmlTextReaderImpl
(_reader
的实际类型)可能会缓存整个文本并降低性能。您可能还必须为这件事编写自己的胆量。
public class FilteredXmlReader : XmlReader
{
public Func<XmlReader, bool> Filter;
private XmlReader _reader;
private FilteredXmlReader(TextReader input, Func<XmlReader, bool> filterProc)
{
Filter = filterProc;
_reader = XmlReader.Create(input);
}
public static new XmlReader Create(TextReader input, Func<XmlReader, bool> filterProc)
{
return new FilteredXmlReader(input, filterProc);
}
public override bool Read()
{
var b = _reader.Read();
while (!(bool)Filter?.Invoke(_reader))
{
b = _reader.Read();
}
return b;
}
#region Wrapper Boilerplate
public override XmlNodeType NodeType => _reader.NodeType;
public override string LocalName => _reader.LocalName;
public override string NamespaceURI => _reader.NamespaceURI;
public override string Prefix => _reader.Prefix;
public override string Value => _reader.Value;
public override int Depth => _reader.Depth;
public override string BaseURI => _reader.BaseURI;
public override bool IsEmptyElement => _reader.IsEmptyElement;
public override int AttributeCount => _reader.AttributeCount;
public override bool EOF => _reader.EOF;
public override ReadState ReadState => _reader.ReadState;
public override XmlNameTable NameTable => _reader.NameTable;
public override string GetAttribute(string name) => _reader.GetAttribute(name);
public override string GetAttribute(string name, string namespaceURI) => _reader.GetAttribute(name, namespaceURI);
public override string GetAttribute(int i) => _reader.GetAttribute(i);
public override string LookupNamespace(string prefix) => _reader.LookupNamespace(prefix);
public override bool MoveToAttribute(string name) => _reader.MoveToAttribute(name);
public override bool MoveToAttribute(string name, string ns) => _reader.MoveToAttribute(name, ns);
public override bool MoveToElement() => _reader.MoveToElement();
public override bool MoveToFirstAttribute() => _reader.MoveToFirstAttribute();
public override bool MoveToNextAttribute() => _reader.MoveToNextAttribute();
public override bool ReadAttributeValue() => _reader.ReadAttributeValue();
public override void ResolveEntity() => _reader.ResolveEntity();
#endregion Wrapper Boilerplate
}
用法:
var xml = "<test />";
XmlDocument doc = new XmlDocument();
XmlReader rdr = FilteredXmlReader.Create(new System.IO.StringReader(xml),
r => r?.Value.Length < 20);
var filteredXML = doc.OuterXml;