从XmlReader获取当前位置

时间:2010-01-29 07:32:18

标签: .net xmlreader

有没有办法在XmlReader检查的节点流中获取当前位置?

我想使用XmlReader解析文档并保存某些元素的位置,以便我以后可以搜索它们。

附录:

我正在通过WPF控件生成Xaml。 Xaml不应经常更改。在Xaml中有占位符,我需要替换项​​目,有时循环。我认为在代码中而不是转换可能更容易(我可能错了)。我的想法是将其解析为需要替换的简单数据结构及其位置,然后使用StringBuilder通过复制xaml字符串中的块来生成最终输出。

9 个答案:

答案 0 :(得分:9)

正如Jon Skeet所说,{ "name": "lib-project", "version": "0.1.0", "description": "description here", "main": "dist/index.js", "scripts": {}, "author": "", "license": "MIT", "dependencies": { } } 实施XmlTextReaderIXmlLineInfoXmlTextReader以来已被弃用,问题仅为.NET 2.0。 我找到了这个解决方案:

XmlReader

P.S。测试.NET Compact Framework 3.5,但也适用于其他人。

答案 1 :(得分:8)

在提出建议之前,只需提出一条建议: 可以保留对您传入XmlReader的基础流的引用,并记下其位置 - 但这会给出你得到了错误的结果,因为读者几乎肯定会缓冲它的输入(即它会读取前1024个字符或其他任何东西 - 所以你的第一个节点可能“出现”在1024字符处。)

如果您使用XmlTextReader而非XmlReader,则会实施IXmlLineInfo,这意味着您可以随时要求LineNumberLinePosition - 这对你来说足够好吗? (你应该首先检查HasLineInfo(),不可否认。)

编辑:我刚刚注意到你希望以后能够找到那个位置......在这种情况下,行信息可能不会非常有用。它非常适合在文本编辑器中查找内容,但对于移动文件指针却不是那么好。你能提供一些关于你想做什么的更多信息吗?可能有更好的方法来解决问题。

答案 2 :(得分:8)

我已经为此开发了一个解决方案,虽然它可能在每个场景中都不起作用并且使用针对.NET Framework类的私有成员的反射,但我能够计算XmlReader的正确位置。扩展方法如下所示。

您的XmlReader必须使用基础StreamReaderFileStream创建(我还没有尝试过其他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);
            }
        }
    }