有没有办法在XmlReader检查的节点流中获取当前位置?
我想使用XmlReader解析文档并保存某些元素的位置,以便我以后可以搜索它们。
附录:
我正在通过WPF控件生成Xaml。 Xaml不应经常更改。在Xaml中有占位符,我需要替换项目,有时循环。我认为在代码中而不是转换可能更容易(我可能错了)。我的想法是将其解析为需要替换的简单数据结构及其位置,然后使用StringBuilder通过复制xaml字符串中的块来生成最终输出。
答案 0 :(得分:9)
正如Jon Skeet所说,{
"name": "lib-project",
"version": "0.1.0",
"description": "description here",
"main": "dist/index.js",
"scripts": {},
"author": "",
"license": "MIT",
"dependencies": {
}
}
实施XmlTextReader
但IXmlLineInfo
自XmlTextReader
以来已被弃用,问题仅为.NET 2.0
。
我找到了这个解决方案:
XmlReader
P.S。测试.NET Compact Framework 3.5,但也适用于其他人。
答案 1 :(得分:8)
在提出建议之前,只需提出一条建议: 可以保留对您传入XmlReader
的基础流的引用,并记下其位置 - 但这会给出你得到了错误的结果,因为读者几乎肯定会缓冲它的输入(即它会读取前1024个字符或其他任何东西 - 所以你的第一个节点可能“出现”在1024字符处。)
如果您使用XmlTextReader
而非XmlReader
,则会实施IXmlLineInfo
,这意味着您可以随时要求LineNumber
和LinePosition
- 这对你来说足够好吗? (你应该首先检查HasLineInfo()
,不可否认。)
编辑:我刚刚注意到你希望以后能够找到那个位置......在这种情况下,行信息可能不会非常有用。它非常适合在文本编辑器中查找内容,但对于移动文件指针却不是那么好。你能提供一些关于你想做什么的更多信息吗?可能有更好的方法来解决问题。
答案 2 :(得分:8)
我已经为此开发了一个解决方案,虽然它可能在每个场景中都不起作用并且使用针对.NET Framework类的私有成员的反射,但我能够计算XmlReader
的正确位置。扩展方法如下所示。
您的XmlReader
必须使用基础StreamReader
从FileStream
创建(我还没有尝试过其他Streams
,只要他们可以正常工作报告他们的立场)。
我在此处发布了详细信息:http://g-m-a-c.blogspot.com/2013/11/determine-exact-position-of-xmlreader.html
public static class XmlReaderExtensions
{
private const long DefaultStreamReaderBufferSize = 1024;
public static long GetPosition(this XmlReader xr, StreamReader underlyingStreamReader)
{
// Get the position of the FileStream
long fileStreamPos = underlyingStreamReader.BaseStream.Position;
// Get current XmlReader state
long xmlReaderBufferLength = GetXmlReaderBufferLength(xr);
long xmlReaderBufferPos = GetXmlReaderBufferPosition(xr);
// Get current StreamReader state
long streamReaderBufferLength = GetStreamReaderBufferLength(underlyingStreamReader);
int streamReaderBufferPos = GetStreamReaderBufferPos(underlyingStreamReader);
long preambleSize = GetStreamReaderPreambleSize(underlyingStreamReader);
// Calculate the actual file position
long pos = fileStreamPos
- (streamReaderBufferLength == DefaultStreamReaderBufferSize ? DefaultStreamReaderBufferSize : 0)
- xmlReaderBufferLength
+ xmlReaderBufferPos + streamReaderBufferPos - preambleSize;
return pos;
}
#region Supporting methods
private static PropertyInfo _xmlReaderBufferSizeProperty;
private static long GetXmlReaderBufferLength(XmlReader xr)
{
if (_xmlReaderBufferSizeProperty == null)
{
_xmlReaderBufferSizeProperty = xr.GetType()
.GetProperty("DtdParserProxy_ParsingBufferLength",
BindingFlags.Instance | BindingFlags.NonPublic);
}
return (int) _xmlReaderBufferSizeProperty.GetValue(xr);
}
private static PropertyInfo _xmlReaderBufferPositionProperty;
private static int GetXmlReaderBufferPosition(XmlReader xr)
{
if (_xmlReaderBufferPositionProperty == null)
{
_xmlReaderBufferPositionProperty = xr.GetType()
.GetProperty("DtdParserProxy_CurrentPosition",
BindingFlags.Instance | BindingFlags.NonPublic);
}
return (int) _xmlReaderBufferPositionProperty.GetValue(xr);
}
private static PropertyInfo _streamReaderPreambleProperty;
private static long GetStreamReaderPreambleSize(StreamReader sr)
{
if (_streamReaderPreambleProperty == null)
{
_streamReaderPreambleProperty = sr.GetType()
.GetProperty("Preamble_Prop",
BindingFlags.Instance | BindingFlags.NonPublic);
}
return ((byte[]) _streamReaderPreambleProperty.GetValue(sr)).Length;
}
private static PropertyInfo _streamReaderByteLenProperty;
private static long GetStreamReaderBufferLength(StreamReader sr)
{
if (_streamReaderByteLenProperty == null)
{
_streamReaderByteLenProperty = sr.GetType()
.GetProperty("ByteLen_Prop",
BindingFlags.Instance | BindingFlags.NonPublic);
}
return (int) _streamReaderByteLenProperty.GetValue(sr);
}
private static PropertyInfo _streamReaderBufferPositionProperty;
private static int GetStreamReaderBufferPos(StreamReader sr)
{
if (_streamReaderBufferPositionProperty == null)
{
_streamReaderBufferPositionProperty = sr.GetType()
.GetProperty("CharPos_Prop",
BindingFlags.Instance | BindingFlags.NonPublic);
}
return (int) _streamReaderBufferPositionProperty.GetValue(sr);
}
#endregion
}
答案 3 :(得分:3)
我遇到同样的问题,显然没有简单的解决方案。
所以我决定操作两个只读的FileStream:一个用于XmlReader,另一个用于获取每一行的位置:
private void ReadXmlWithLineOffset()
{
string malformedXml = "<test>\n<test2>\r <test3><test4>\r\n<test5>Thi is\r\ra\ntest</test5></test4></test3></test2>";
string fileName = "test.xml";
File.WriteAllText(fileName, malformedXml);
XmlTextReader xr = new XmlTextReader(new FileStream(fileName, FileMode.Open, FileAccess.Read));
FileStream fs2 = new FileStream(fileName, FileMode.Open, FileAccess.Read);
try
{
int currentLine = 1;
while(xr.Read())
{
if (!string.IsNullOrEmpty(xr.Name))
{
for (;currentLine < xr.LineNumber; currentLine++)
ReadLine(fs2);
Console.WriteLine("{0} : LineNum={1}, FileOffset={2}", xr.Name, xr.LineNumber, fs2.Position);
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception : " + ex.Message);
}
finally
{
xr.Close();
fs2.Dispose();
}
}
private void ReadLine(FileStream fs)
{
int b;
while ((b = fs.ReadByte()) >= 0)
{
if (b == 10) // \n
return;
if (b == 13) // \r
{
if (fs.ReadByte() != 10) // if not \r\n, go back one byte
fs.Seek(-1, SeekOrigin.Current);
return;
}
}
}
这不是最好的方法,因为它使用了两个读者。为避免这种情况,我们可以重写在XmlReader和行计数器之间共享的新FileReader。 但它只是给你你感兴趣的线的偏移量。 为了获得标签的确切偏移量,我们应该使用LinePosition,但由于编码,这可能很棘手。
答案 4 :(得分:2)
感谢杰夫的回答。它在Windows 7上运行得很好。但是在mscorlib.dll的Windows server 2003上以某种方式使用.net 4版本,我不得不改变以下2个功能才能工作。
private long GetStreamReaderBufferLength(StreamReader sr)
{
FieldInfo _streamReaderByteLenField = sr.GetType()
.GetField("charLen",
BindingFlags.Instance | BindingFlags.NonPublic);
var fValue = (int)_streamReaderByteLenField.GetValue(sr);
return fValue;
}
private int GetStreamReaderBufferPos(StreamReader sr)
{
FieldInfo _streamReaderBufferPositionField = sr.GetType()
.GetField("charPos",
BindingFlags.Instance | BindingFlags.NonPublic);
int fvalue = (int)_streamReaderBufferPositionField.GetValue(sr);
return fvalue;
}
此外,GetPosition方法中的underlyingStreamReader应该是窥视推进指针。
private long GetPosition(XmlReader xr, StreamReader underlyingStreamReader)
{
long pos = -1;
while (pos < 0)
{
// Get the position of the FileStream
underlyingStreamReader.Peek();
long fileStreamPos = underlyingStreamReader.BaseStream.Position;
// long fileStreamPos = GetStreamReaderBasePosition(underlyingStreamReader);
// Get current XmlReader state
long xmlReaderBufferLength = GetXmlReaderBufferLength(xr);
long xmlReaderBufferPos = GetXmlReaderBufferPosition(xr);
// Get current StreamReader state
long streamReaderBufferLength = GetStreamReaderBufferLength(underlyingStreamReader);
long streamReaderBufferPos = GetStreamReaderBufferPos(underlyingStreamReader);
long preambleSize = GetStreamReaderPreambleSize(underlyingStreamReader);
// Calculate the actual file position
pos = fileStreamPos
- (streamReaderBufferLength == DefaultStreamReaderBufferSize ? DefaultStreamReaderBufferSize : 0)
- xmlReaderBufferLength
+ xmlReaderBufferPos + streamReaderBufferPos;// -preambleSize;
}
return pos;
}
答案 5 :(得分:1)
def endoflevel1():
global score, gamemode, gamestart, level
screen.clear()
screen.fill("green")
screen.draw.text("Congratulations! You have successfully completed the 1st level!", topleft=(100,350), fontsize=30, color = "black")
nextlevel.draw()
gamestart = 0
pygame.display.flip()
running = True
while (running):
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
if nextlevel.collidepoint(event.pos):
score = 0
gamemode = 3
gamestart = 1
level = 2
running = False
答案 6 :(得分:0)
public partial class Frm_hauptfenster : Form
{
//Attribute
Kunde[] kundenfeld = new Kunde[0];
public Frm_hauptfenster()
{
InitializeComponent();
}
//Daten auslesen aus einer XML-Datei
private void btn_lesen_Click(object sender, EventArgs e)
{
int ku = 0;
string na = "";
string vo = "";
int i = 0;
dGV_ausgabe.RowCount = 1;
dGV_ausgabe.ColumnCount = 3;
dGV_ausgabe.RowHeadersVisible = false;
dGV_ausgabe.ColumnHeadersVisible = false;
dGV_ausgabe.Rows.Add("Kundennummer", "Name", "Vorname");
//openfile dialog zum oeffnen der xml datei
OpenFileDialog ofd = new OpenFileDialog()
{
Filter = "Texte (*.xml)|*.xml|Alle Dateien (*.*)|*.*",
Title = "Datei öffnen"
};
if (ofd.ShowDialog() == DialogResult.OK)
{
//leert die richTextBox
riTB_ausgabe.Clear();
XmlTextReader xr = new XmlTextReader(ofd.FileName);
while (xr.Read())
{
if (xr.NodeType == XmlNodeType.Element)
{
if (xr.AttributeCount > 0)
{
while (xr.MoveToNextAttribute())
{
switch (xr.Name)
{
case "kundennummer":
ku = Convert.ToInt32(xr.Value);
break;
case "name":
na = xr.Value;
break;
case "vorname":
vo = xr.Value;
break;
}
riTB_ausgabe.Text +=
xr.Name + " -> " + xr.Value + "\n";
}
riTB_ausgabe.Text += "\n";
//Array erweitern
Array.Resize(ref kundenfeld, kundenfeld.Count() + 1);
kundenfeld[i] = new Kunde(ku, na, vo);
i++;
dGV_ausgabe.Rows.Add(ku, na, vo);
}
}
}
xr.Close();
}
}
private void btt_kunde_hinzufuegen_Click(object sender, EventArgs e)
{
if(txt_knr.Text!="" && txt_name.Text != "" && txt_vorname.Text!="")
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Xml-Datei(.xml)|*.xml";
if (sfd.ShowDialog() == DialogResult.OK)
{
XmlTextWriter xw = new XmlTextWriter(sfd.FileName, new UnicodeEncoding());
Kunde k = new Kunde(Convert.ToInt16(txt_knr.Text), Convert.ToString(txt_name.Text), Convert.ToString(txt_vorname.Text));
Array.Resize(ref kundenfeld, kundenfeld.Count() + 1);
kundenfeld[kundenfeld.Count() - 1] = k;
xw.WriteStartDocument();
xw.WriteStartElement("Kundenliste");
foreach (Kunde k1 in kundenfeld)
{
k1.AlsXmlElementSchreiben(xw);
}
xw.WriteEndElement();
xw.Close();
}
}
else { MessageBox.Show("eingabe überprüfen", "Fehler"); }
}
}
class Kunde
{
//Attribute
private int knr;
private string name;
private string vname;
//get-set Methode zum erhalten bzw. setzen einer Kundennummer
public int Knr
{
get { return this.knr; }
private set { this.knr = value; }
}
public string Name
{
get { return this.name; }
private set { this.name = value; }
}
public string Vname
{
get { return this.vname; }
private set { this.vname = value; }
}
//Konstruktor
public Kunde(int ku, string na, string vo)
{
this.Knr = ku;
this.Name = na;
this.Vname = vo;
}
//Methoden
public string ausgebenWerte()
{
string text;
text = "Kundennummer: " + this.Knr + "\nName: " + this.Name + "\nVorname: " + this.Vname;
return text;
}
public void AlsXmlElementSchreiben(XmlTextWriter xw)
{
xw.WriteStartElement("Kunde");
xw.WriteAttributeString("kundennummer", Convert.ToString(knr));
xw.WriteAttributeString("name", name);
xw.WriteAttributeString("vorname", vname);
xw.WriteEndElement();
}
}
答案 7 :(得分:0)
class Auto
{
private string bestizter;
private string modell;
private int leistung;
private string beschleunigung;
private string farbe;
public Auto(XmlReader xr)
{
while(xr.Read())
{
if (xr.NodeType == XmlNodeType.Element)
{
switch(xr.Name)
{
case "bestizter":
// weiterlesen zum Textknoten
xr.Read();
// Textinhalt auf Klasseneigenschaft kopieren
bestizter = xr.Value;
break;
case "modell":
xr.Read();
modell = xr.Value;
break;
case "leistung":
xr.Read();
leistung = Convert.ToInt32(xr.Value);
break;
case "beschleunigung":
xr.Read();
beschleunigung = xr.Value;
break;
case "farbe":
xr.Read();
farbe = xr.Value;
break;
}
}
}
}
public string GetBestitzer()
{
return bestizter;
}
public string GetModell()
{
return modell;
}
public string GetLeistung()
{
return Convert.ToString(leistung);
}
public string GetBeschleunigung()
{
return beschleunigung;
}
public string GetFarbe()
{
return farbe;
}
}
答案 8 :(得分:0)
private OleDbConnection connection = new OleDbConnection();
private OleDbCommand command = new OleDbCommand();
private OleDbDataReader reader;
OpenFileDialog ofd = new OpenFileDialog();
//Attribute
string[] zeile = new string[]{"Name#Herkunft,Zugehöhrigkeit#Spieler#Manschafts_ID#bezahlt"};
public Form1()
{
InitializeComponent();
if(ofd.ShowDialog() == DialogResult.OK)//connection string
{
connection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + ofd.FileName;
}
}
private void btt_auflisten_Click(object sender, EventArgs e)
{
//auslesen
auslesen(connection, command, reader, "SELECT * FROM mannschaften");
//Teilnahemerformular wert übergeben und öffnen
Teilnehmerformular t1 = new Teilnehmerformular(zeile);
t1.ShowDialog();
}
//methode zum auslesen
private void auslesen(OleDbConnection Verbindung, OleDbCommand Befehl, OleDbDataReader Leser, string sql)
{
//Attribute
string name;
string her;
string zu;
string sp;
Mannschaft[] mliste=new Mannschaft[0];
string datensatz = "";
try
{
Befehl.Connection = Verbindung;
Befehl.CommandText = sql;
Verbindung.Open();
Leser = Befehl.ExecuteReader();
while(Leser.Read())
{
for(int Spalte = 0; Spalte < Leser.FieldCount; Spalte++)
{
datensatz += Leser[Spalte] + "#";
//zumschreiben in´txt und abspeichern in array
if (Leser[Spalte] == Leser["Mname"]) name = Leser[Spalte].ToString();
if (Leser[Spalte] == Leser["MHerkunft"]) her = Leser[Spalte].ToString();
if (Leser[Spalte] == Leser["MZugehoerigkeit"]) zu = Leser[Spalte].ToString();
if (Leser[Spalte] == Leser["MSpieler"]) sp = Leser[Spalte].ToString();
}
Array.Resize(ref zeile, zeile.Count() + 1);
zeile[zeile.Count()-1] = datensatz;
datensatz = "";
//abspeichern in array nicht funktioniert
//Mannschaft m1 = new Mannschaft(name, her, zu, sp);
// Array.Resize(ref mliste, mliste.Count() + 1);
//mliste[mliste.Count() - 1] = m1;
dGV_ausgabe.Rows.Add(Leser["MName"], Leser["MHerkunft"], Leser["MZugehoerigkeit"], Leser["MSpieler"]);
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Fehlermeldung");
}
Leser.Close();
Verbindung.Close();
}
private void btt_aufnehmen_Click(object sender, EventArgs e)
{
hinzufügen_formular hin = new hinzufügen_formular();
hin.ShowDialog();
}
private void btt_statistik_Click(object sender, EventArgs e)
{
string statistik="";
string anzahl = "";
//gesammtspieleranzahl
try
{
command.Connection = connection;
command.CommandText = "SELECT SUM(mannschaften.MSpieler) FROM mannschaften";
connection.Open();
statistik = command.ExecuteScalar().ToString();;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Fehlermeldung");
}
connection.Close();
//anzahl mannschaften
try
{
command.Connection = connection;
command.CommandText = "SELECT COUNT(MName) FROM mannschaften";
connection.Open();
anzahl = command.ExecuteScalar().ToString(); ;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Fehlermeldung");
}
connection.Close();
Statistik st = new Statistik(statistik,anzahl);
st.ShowDialog();
}
private void btt_speichern_Click(object sender, EventArgs e)
{
SaveFileDialog ofd_2 = new SaveFileDialog();
if(ofd_2.ShowDialog() == DialogResult.OK)
{
FileStream fs = new FileStream(ofd_2.FileName, FileMode.Append);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(zeile);
}
}
}