How do i get xml nodes from the xmlnodelist

2019-07-23 18:33发布

问题:

I want to get the sub nodes list that are within my table called data. i have managed to get the value nodes and loop throw each. now i want to do the same as for the nodes within my comment tag. i have no idea on how can i get the nodes within the comment tag(font,datestamp and comment).

<data name="Exit_Button" xml:space="preserve">
<value>Exit Finger Enrolment</value>
<comment>[Font]Regular[/Font][DateStamp]2014/012/01 00:00:00[/DateStamp]     [Comment] this is a comment.!![/Comment]</comment>

i have done this for value and it is working

            XmlDocument _doc = new XmlDocument();
            _doc.Load(outputFilePath);
            string xmlcontents = _doc.InnerXml;
            XmlNodeList _value = _doc.GetElementsByTagName("data");

            foreach( XmlNode x in _value)
            {
                XmlNodeList y = x.ChildNodes;
                for(int i = 0; i < y.Count; i++)
                {
                   XmlNode z = y.Item(i);
                   if (z.Name.Contains("value"))
                   {
                   }
                }
            }

回答1:

To do the job you could form an aggregate like this:

public class ResxFile
{
    #region fields

    private XDocument doc; //this is the aggregate
    private IResxFileDataNode[] nodes;

    #endregion

    #region properties

    public IResxFileDataNode[] DataNodes { get { return nodes; } }

    #endregion

    #region construction

    //private constructor to avoid missuse of the class
    private ResxFile(string path)
    {
        this.doc = XDocument.Load(path);
    }


    //use this instead
    public static ResxFile Load(string path)
    {
        ResxFile result = new ResxFile(path);
        result.CreateDataNodes();
        return result;
    }

    #endregion

    #region methods

    private void CreateDataNodes()
    {
        this.nodes = doc.Descendants("data").Select(n => new ResxFileDataNode(n)).ToArray();
    }

    public void Save(string path)
    {
        this.doc.Save(path);
    }

    #endregion
}

public interface IResxFileDataNode : INotifyPropertyChanged
{
    string Name { get; } //readonly field
    string Value { get; set; } //this you can edit
    string Font { get; set; } // i'd bind this to a combobox with all possible values
    string DateStamp { get; } //i assume this is readonly and will be set to the current time once you update the fields
    string Comment { get; set; }
}

public class ResxFileDataNode : IResxFileDataNode
{
    #region fields

    private static readonly Regex fontRegex = new Regex(@"(?<=\[Font\]).*?(?=\[/Font\])");
    private static readonly Regex dateRegex = new Regex(@"(?<=\[DateStamp\]).*?(?=\[/DateStamp\])");
    private static readonly Regex commentRegex = new Regex(@"(?<=\[Comment\]).*?(?=\[/Comment\])");
    private static readonly string dateTimeFormat = "yyyy/dd/MM HH:mm:ss";

    private XElement node; //this is the aggregate
    private XElement valueNode;
    private XElement commentNode;

    private string name;
    private string value;
    private string font;
    private DateTime dateTime;
    private string comment;

    #endregion

    #region properties

    public string Name
    {
        get { return this.name; }
    }

    public string Value
    {
        get
        {
            return this.value;
        }
        set
        {
            this.value = value;
            valueNode.Value = this.value;
            UpdateTimeStamp();
            OnPropertyChanged("Value");
        }
    }

    public string Font
    {
        get
        {
            return this.font;
        }
        set
        {
            this.font = value;
            UpdateTimeStamp();
            OnPropertyChanged("Font");
        }
    }

    public string DateStamp
    {
        get { return this.dateTime.ToString(dateTimeFormat); }
    }

    public string Comment
    {
        get
        {
            return this.comment;
        }
        set
        {
            this.comment = value;
            UpdateTimeStamp();
            OnPropertyChanged("Comment");
        }
    }

    #endregion

    #region construction

    public ResxFileDataNode(XElement dataNode)
    {
        this.node = dataNode;
        this.valueNode = dataNode.Element("value");
        this.value = this.valueNode.Value;
        this.commentNode = dataNode.Element("comment");
        this.name = dataNode.Attribute("name").Value;
        this.comment = commentRegex.Match(this.commentNode.Value).Value;
        this.font = fontRegex.Match(this.commentNode.Value).Value;

        DateTime d;
        if (DateTime.TryParseExact(dateRegex.Match(this.commentNode.Value).Value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out d))
        {
            this.dateTime = d;
        }
    }

    #endregion

    #region methods

    private void OnPropertyChanged(string propertyName)
    { 
        PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
    }

    private void UpdateTimeStamp()
    {
        this.dateTime = DateTime.Now;
        UpdateCommentNode();
        OnPropertyChanged("DateStamp");
    }

    private void UpdateCommentNode()
    {
        this.commentNode.Value = string.Format("[Font]{0}[/Font][DateStamp]{1}[/DateStamp][Comment]{2}[/Comment]", this.font.ToString(), this.dateTime.ToString(dateTimeFormat,CultureInfo.InvariantCulture), this.comment);
    }

    #endregion

    #region events

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    #endregion

}   

and use it with binding to a datagridview:

public partial class Form1 : Form
{
    private ResxFile file;

    public Form1()
    {
        InitializeComponent();
    }

    private void btnLoad_Click(object sender, EventArgs e)
    {
        file = ResxFile.Load("XMLFile1.xml"); //open a openfiledialog here to get the actual filename

        var source = new BindingSource(file.DataNodes, null);

        dataGridView1.DataSource = source;

    }

    private void btnSave_Click(object sender, EventArgs e)
    {
        file.Save("XMLFile1.xml"); //open a savefiledialog here to get the actual filename
    }
}


回答2:

If this is your xml:

<?xml version="1.0" encoding="utf-8"?>
    <data name="Exit_Button" xml:space="preserve">
    <value>Exit Finger Enrolment</value>
    <comment>[Font]Regular[/Font][DateStamp]2014/012/01 00:00:00[/DateStamp]     [Comment] this is a comment.!![/Comment]</comment>
</data>

Then I've extracted your node like this:

var root = XElement.Load(@"Path/to/your/file");
var result = root.Elements("comment").FirstOrDefault().Value;

To get the values in between the tags, I've borrowed a solution from Dmitry Bychenko:

public static class Extensions
{
   public static string ParseFromString(this string source, string start, string end)
   {
        int From = source.IndexOf(start) + start.Length;
        int To = source.LastIndexOf(end);

        string result = source.Substring(From, To - From);
        return result;
   }
}

And use it like this:

var font = result.ParseFromString("[Font]", "[/Font]");
var DateStamp = result.ParseFromString("[DateStamp]","[/DateStamp]");
var comment = result.ParseFromString("[Comment]","[/Comment]");


回答3:

Your <comment>...</comment> ends up in a special XmlNode type called an XmlElement. So once you get the correct XmlElement, the one with the comment tag, you just need to read its InnerText property.

See MSDN for more at https://msdn.microsoft.com/en-us/library/system.xml.xmlelement.innertext%28v=vs.110%29.aspx.



标签: c# xml xmlnode