1

I've got this XML:

<?xml version="1.0" encoding="utf-8"?>
<JMF SenderID="InkZone-Controller" Version="1.2">
  <Command ID="cmd.00695" Type="Resource">
    <ResourceCmdParams ResourceName="InkZoneProfile" JobID="K_41">
      <InkZoneProfile ID="r0013" Class="Parameter" Locked="false" Status="Available" PartIDKeys="SignatureName SheetName Side Separation" DescriptiveName="Schieberwerte von DI" ZoneWidth="32">
        <InkZoneProfile SignatureName="SIG1">
          <InkZoneProfile Locked="False" SheetName="S1">
            <InkZoneProfile Side="Front">
              <ColorPool Class="Parameter" DescriptiveName="Colors for the job" Status="Available">
                <InkZoneProfile Separation="PANTONE 647 C" ZoneSettingsX="0 0,003 " />
              </ColorPool>
            </InkZoneProfile>
          </InkZoneProfile>
        </InkZoneProfile>
      </InkZoneProfile>
    </ResourceCmdParams>
  </Command>
</JMF>

I'm trying to add a node after a specific node() , using XElement and Linq. But my LINQ query always returns me null. Tried this:

            XElement InkZonePath = XmlDoc.Element("JMF").Elements("InkZoneProfile").Where(z => z.Element("InkZoneProfile").Attribute("Side").Value == "Front").SingleOrDefault();

And this:

            XmlDoc.Element("JMF")
                   .Elements("InkZoneProfile").Where(InkZoneProfile => InkZoneProfile.Attribute("Side")
                   .Value == "Front").FirstOrDefault().AddAfterSelf(new XElement("InkZoneProfile",
                   new XAttribute("Separation", x.colorname),
                   new XAttribute("ZoneSettingsX", x.colorvalues)));

I've built this queries following those examples:

Select XElement where child element has a value

Insert XElements after a specific node

LINQ-to-XML XElement query NULL

But it didn't worked as expected. What is wrong with the LINQ Query ? From what i've read it should work (logically reading the expression i can understand it).

Thanks

EDIT-1: Entire writexml Method

public void writexml(xmldatalist XMLList, variables GlobalVars)
        {

            XmlWriterSettings settings = new XmlWriterSettings
            {
                Indent = true,
                IndentChars = "\t",
                NewLineChars = Environment.NewLine,
                NewLineHandling = NewLineHandling.Replace,
                Encoding = new UTF8Encoding(false)
            };

            string DesktopFolder = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
            string FileExtension = ".xml";
            string PathString = Path.Combine(DesktopFolder, "XML");
            System.IO.Directory.CreateDirectory(PathString);


            foreach (List<xmldata> i in XMLList.XMLArrayList)
            {
                int m = 0;
                foreach (var x in i)
                {

                    string XMLFilename = System.IO.Path.GetFileNameWithoutExtension(x.xml_filename);                    
                    GlobalVars.FullPath = Path.Combine(PathString, XMLFilename + FileExtension);


                    if (!File.Exists(GlobalVars.FullPath))
                    {
                        XDocument doc = new XDocument(
                         new XDeclaration("1.0", "utf-8", "yes"),

                         new XElement("JMF",
                             new XAttribute("SenderID", "InkZone-Controller"),
                             new XAttribute("Version", "1.2"),
                        new XElement("Command",
                             new XAttribute("ID", "cmd.00695"),
                             new XAttribute("Type", "Resource"),
                        new XElement("ResourceCmdParams",
                            new XAttribute("ResourceName", "InkZoneProfile"),
                            new XAttribute("JobID", "K_41"),
                        new XElement("InkZoneProfile",
                            new XAttribute("ID", "r0013"),
                            new XAttribute("Class", "Parameter"),
                            new XAttribute("Locked", "False"),
                            new XAttribute("Status", "Available"),
                            new XAttribute("PartIDKeys", "SignatureName SheetName Side Separation"),
                            new XAttribute("DescriptiveName", "Schieberwerte von DI"),
                            new XAttribute("ZoneWidth", "32"),
                        new XElement("InkZoneProfile",
                            new XAttribute("SignatureName", "SIG1"),
                        new XElement("InkZoneProfile",
                            new XAttribute("Locked", "false"),
                            new XAttribute("SheetName", "S1"),
                        new XElement("InkZoneProfile",
                            new XAttribute("Side", "Front"),
                        new XElement("ColorPoolClass",
                            new XAttribute("Class", "Parameter"),
                            new XAttribute("DescriptiveName", "Colors for the job"),
                            new XAttribute("Status", "Available")
                            )))))))));
                        doc.Save(GlobalVars.FullPath);

                        XDocument XmlDoc = new XDocument();
                        XmlDoc = XDocument.Load(GlobalVars.FullPath);
                        XElement InkZonePath = XmlDoc.Root.Descendants("InkZoneProfile").Where(z => (string)z.Attribute("Side") == "Front").SingleOrDefault();

                        if (InkZonePath != null)
                        {
                            InkZonePath.AddAfterSelf(new XElement("InkZoneProfile",
                                   new XAttribute("Separation", x.colorname),
                                   new XAttribute("ZoneSettingsX", x.colorvalues)));

                        }
                        XmlDoc.Save(GlobalVars.FullPath);

                        }//Closing !FileExists
                    }//Closing inner foreach


            }//Closing outer foreach


        }//Closing writexml method
Community
  • 1
  • 1
Pablo Costa
  • 125
  • 4
  • 14

3 Answers3

2

The problem with your current code is here : Element("JMF").Elements("InkZoneProfile") Since InkZoneProfile is not a direct child of JMF it will not return anything. Use Descendants instead.

Check difference between Elements & Descendants.

This should give you correct result:-

 XElement InkZonePath = xdoc.Element("JMF").Descendants("InkZoneProfile")
                            .SingleOrDefault(z => (string)z.Attribute("Side") == "Front")

After this you can add whatever node you want to add using AddAfterSelf. Also note I have used SingleOrDefault here, but you may get exception if you have multiple matching nodes with this, In that case consider using FirstOrDefault.

Update:

To add new node:-

if (InkZonePath != null)
{
    InkZonePath.AddAfterSelf(new XElement("InkZoneProfile",
                             new XAttribute("Separation", "Test"),
                             new XAttribute("ZoneSettingsX", "Test2")));
}
//Save XDocument                              
xdoc.Save(@"C:\Foo.xml");
Community
  • 1
  • 1
Rahul Singh
  • 21,585
  • 6
  • 41
  • 56
  • IT worked. Thanks. Now i'm just having some trouble to add this new XElement to the xdoc – Pablo Costa Feb 29 '16 at 15:15
  • 1
    @PabloCosta - What is the problem? Simply check if `InkZonePath` is not null. Then say: `InkZonePath.AddAfterSelf(new XElement("InkZoneProfile",...` after that Save the **XmlDoc** like this `XmlDoc.Save(..Path);` – Rahul Singh Feb 29 '16 at 15:22
  • InkZonePath isn't null (checked with the debugger). Then i run the commands (InkZonePath.AddAfterSelf ......) and nothing happens. If i add some XmlDoc.Save , it'll show only the last loop iteration. I'l post a new question and link it here. – Pablo Costa Feb 29 '16 at 15:23
  • Yeah Rahul. Its exactly what i did. But this adds only the last loop iteration to the file. Suppose i have 5 Elements with attributes "Separation" and "ZoneSettingsX". Only the 5th one will be shown in the file. Please check here: http://pastebin.com/GCSZz6GF - its the new question (90 min post limit). – Pablo Costa Feb 29 '16 at 15:30
  • @PabloCosta - I am not sure what you are doing wrong. I have used the above code and it's working fine for me. – Rahul Singh Feb 29 '16 at 15:38
  • 1
    @PabloCosta -I never knew you are doing all this inside a loop, looks messy. Please debug it and check the XML file after each save. – Rahul Singh Feb 29 '16 at 15:51
  • Whem debugging using Console.Writeline (xmlDoc) , each iteration shows the file with only one element. Like , first iteration will show . Its like there's a new file being created for each iteration, instead of Append. – Pablo Costa Feb 29 '16 at 15:54
  • 1
    Fixed my friend. My fault \ my bad. On the loop's begin there was a command to delete the file if it existed. Since there always was a file in the end of the loop, i was always deleting and creating it from scratch. Now one last question, if i may: My is being added just after the - and i needed it to be added before closing the tag. Is there anything i can do to avoid this behaviour ? I updated the post with correct code. – Pablo Costa Feb 29 '16 at 16:04
1

You need to use Descendants method instead Elements:

XElement InkZonePath = XmlDoc.Root.Descendants("InkZoneProfile").Where(z => (string)z.Attribute("Side") == "Front").SingleOrDefault();

if(InkZonePath !=null)
   InkZonePath.AddAfterSelf(new XElement("InkZoneProfile",
               new XAttribute("Separation", x.colorname),
               new XAttribute("ZoneSettingsX", x.colorvalues)));
ocuenca
  • 38,548
  • 11
  • 89
  • 102
1

you can use Descendants instead.

var node  = XmlDoc.Descendants("InkZoneProfile").Where(x=> x.Attribute("Side") !=null && x.Attribute("Side").Value == "Front").FirstorDefault();
Viru
  • 2,228
  • 2
  • 17
  • 28
  • This throws an exception. Object instance is not set to an instance of an object. – Pablo Costa Feb 29 '16 at 15:00
  • 1
    @PabloCosta Linq query is correct.....what type is your XmlDoc? can you check again? – Viru Feb 29 '16 at 15:07
  • 1
    @PabloCosta yeah found it....HasAttrbutes property was used incorrectly...try new code – Viru Feb 29 '16 at 15:11
  • It worked ! Thanks. But now how do i add this node ? If i just leave this there the data won't be added. And i can't use xmlDoc.Add(node). – Pablo Costa Feb 29 '16 at 15:15
  • @PabloCosta Xelement is reference type so any change you do to this XElement, it is reflected in XmlDoc too – Viru Feb 29 '16 at 15:17
  • If so there's something weird. If i insert an xmlDoc.Save (path) , the XML will contain only the last added item (its happening inside a nested foreach loop). If i do nothing, no content is added. I'll post a new question, seems easier. – Pablo Costa Feb 29 '16 at 15:19