0

I am trying to add (insert) a new <Period></Period> element into the following XML;

<?xml version="1.0" encoding="utf-8"?>
<Scheduler>
  <Module guid="64A3EB4C-7F34-47F3-8894-933CB0048D87">
    <RetrieveDays>1</RetrieveDays>
    <Schedule>
      <Period>1</Period>
      <Period>33</Period>
      <Period>49</Period>
      <Period>73</Period>
    </Schedule>
  </Module>
</Scheduler>

So for example, I pass the value 96, the new XML would look like;

<?xml version="1.0" encoding="utf-8"?>
<Scheduler>
  <Module guid="64A3EB4C-7F34-47F3-8894-933CB0048D87">
    <RetrieveDays>1</RetrieveDays>
    <Schedule>
      <Period>1</Period>
      <Period>33</Period>
      <Period>49</Period>
      <Period>73</Period>
      <Period>96</Period>
    </Schedule>
  </Module>
</Scheduler>

Using the following code;

// period is the new value
XDocument xmlDoc = new XDocument();
xmlDoc = XDocument.Load(String.Format(@"{0}\{1}", settingsDir, settingsFilename));
XElement periodNodes = xmlDoc.Root.Descendants("Module").Where(i => (String)i.Attribute("guid") == moduleGuId).First().Element("Schedule");

if (periodNodes.Descendants("Period").Where(x => x.Value == period.ToString()).Count() == 0)
    periodNodes.Add(new XElement("Period", period.ToString()));

xmlDoc.Save(String.Format(@"{0}\{1}", settingsDir, settingsFilename));

But unfortunately no new <Period></Period> element gets created. I have checked that the XML is valid, which it is. I tried renaming the element, but to no change.

I cannot find a solution, what am I missing?

Update

Well, this is embarrassing: I restarted the computer and VS and now it works - go figure. Nonetheless, thank you all for such quick responses and suggestions.

halfer
  • 19,824
  • 17
  • 99
  • 186
user1224125
  • 21
  • 1
  • 5
  • Have you stepped through it and checked that `periodNodes.Add` is actually called? – Charles Mager Aug 02 '16 at 18:55
  • Before asking us, you can [use the debugger](http://www.codeproject.com/Articles/79508/Mastering-Debugging-in-Visual-Studio-A-Beginn) to step through your code and check whether the clause in your `if` statement actually evaluates to true, and if not, why not – Sam I am says Reinstate Monica Aug 02 '16 at 18:57
  • Check [this fiddle](https://dotnetfiddle.net/Wfh7iq) - your code works fine. If you're still having issues, include a [mcve]. – Charles Mager Aug 02 '16 at 18:58
  • @Charles Mager: I did indeed, and it does step into the periodNodes.Add line. The file also gets saved (datetime stamp checked), but still the line is missing. – user1224125 Aug 02 '16 at 18:59

4 Answers4

1

Be sure not to have the file open in another application and that the account the application is running under has rights to write to that file. Try creating a new file instead, this will eliminate the file write access; unless the user account doesn't have write permissions on that directory.

For testing purposes try changing the final line to this...

xmlDoc.Save(String.Format(@"{0}\{1}2", settingsDir, settingsFilename));
Larry Dukek
  • 2,179
  • 15
  • 16
1

Know that you've figured out the issue but you can eliminate a lot of your code by using XPath.

var schedulerSelect = string.Format("//Module[@guid='{0}']/Schedule",guid);
var periodSelect = string.Format("Period[text()={0}]",period);
var node = doc.XPathSelectElement(schedulerSelect+"/"+periodSelect);

if(node == null)
{
    node = doc.XPathSelectElement(schedulerSelect);

    if(node!=null)
       node.Add(new XElement("Period",period));
}

You can see a working version I created on .NET Fiddle here

konkked
  • 3,161
  • 14
  • 19
0

Use this code

        XDocument doc = XDocument.Load(String.Format(@"{0}\{1}", settingsDir, settingsFilename));
        var query = doc.Descendants("Schedule");
        var q2 = query.Descendants("Period").Where(a => a.Value == period.ToString()).Select(b => b);

        if (q2.Count() == 0)
        {
            query.FirstOrDefault().Add(new XElement("Period", period.ToString()));
            doc.Save(String.Format(@"{0}\{1}", settingsDir, settingsFilename));
        }
Mostafiz
  • 7,243
  • 3
  • 28
  • 42
  • That removes a bunch of the logic for where and when to add the period. And, as the code in the question [actually works fine](https://dotnetfiddle.net/Wfh7iq), it's not clear how this would solve whatever the problem is. – Charles Mager Aug 02 '16 at 19:03
  • @user1224125 see my latest update hope this is what you want – Mostafiz Aug 02 '16 at 19:15
0

In VB using XElement it would look like this,

    Dim xe As XElement
    'to load from a file
    '  xe = XElement.Load("Your Path Here")

    ' for testing
    xe = <Scheduler>
             <Module guid="64A3EB4C-7F34-47F3-8894-933CB0048D87">
                 <RetrieveDays>1</RetrieveDays>
                 <Schedule>
                     <Period>1</Period>
                     <Period>33</Period>
                     <Period>49</Period>
                     <Period>73</Period>
                 </Schedule>
             </Module>
         </Scheduler>

    Dim moduleGuId As String = "64A3EB4C-7F34-47F3-8894-933CB0048D87"
    Dim theVal As Integer = 96

    Dim ie As IEnumerable(Of XElement)
    ie = From el In xe.<Module> Where el.@guid = moduleGuId Take 1
         From sel In el.<Schedule>...<Period> Where sel.Value = theVal.ToString Select sel

    If ie.Count = 0 Then
        xe...<Schedule>.LastOrDefault.Add(<Period><%= theVal %></Period>)
    End If

    '  xe.Save("path here")
dbasnett
  • 11,334
  • 2
  • 25
  • 33