Search code examples
c#xmllinqxelement

XElement add node on specific position not working as expected


I've got the following XML File:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<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" />
              <Color Name="PANTONE 647 C" CMYK="1 1 0 0" sRGB="0 0 1" />
              <Color Name="Black" CMYK="1 1 0 0" sRGB="0 0 1" />
              <Color Name="Yellow" CMYK="1 1 0 0" sRGB="0 0 1" />
              <Color Name="Magenta" CMYK="1 1 0 0" sRGB="0 0 1" />
              <Color Name="Cyan" CMYK="1 1 0 0" sRGB="0 0 1" />
            </InkZoneProfile>
            <InkZoneProfile Separation="Cyan" ZoneSettingsX="0  0,006 0" />
            <InkZoneProfile Separation="Magenta" ZoneSettingsX="0 0,031  0" />
            <InkZoneProfile Separation="Yellow" ZoneSettingsX="0 0,021  0" />
            <InkZoneProfile Separation="Black" ZoneSettingsX="0 0,005  0" />
            <InkZoneProfile Separation="PANTONE 647 C" ZoneSettingsX="0,002 0"/>
          </InkZoneProfile>
        </InkZoneProfile>
      </InkZoneProfile>
    </ResourceCmdParams>
  </Command>
</JMF>

I want to add a node specifically after <InkZoneProfile Side="Front">. I issue the following expression for that:

XElement InkZonePath = XmlDoc.Root.Descendants("InkZoneProfile").Where(z => (string)z.Attribute("Side") == "Front").SingleOrDefault();
var InkZoneProfilePosition = InkZonePath.Parent; 
if (InkZoneProfilePosition != null)
                    {
                        InkZoneProfilePosition.Add(new XElement("InkZoneProfile",
                                    new XAttribute("Separation", x.colorname),
                                    new XAttribute("ZoneSettingsX", x.colorvalues)));
                    }

Instead of adding the node in the position i specified , the node is added just after <ColorPool Class> node - i need it to be just after <InkZoneProfile Side="Front">

Example of the outputh i'm looking for:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<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">
                       <InkZoneProfile Separation="Cyan" ZoneSettingsX="0 0,005 " />
            <InkZoneProfile Separation="Magenta" ZoneSettingsX="0  0" />
            <InkZoneProfile Separation="Yellow" ZoneSettingsX="0 0,021 0" />
            <InkZoneProfile Separation="Black" ZoneSettingsX="0 0,005 " />
            <InkZoneProfile Separation="PANTONE 647 C" ZoneSettingsX="0 0,003 " />
              <ColorPool Class="Parameter" DescriptiveName="Colors for the job" Status="Available" />
              <Color Name="PANTONE 647 C" CMYK="1 1 0 0" sRGB="0 0 1" />
              <Color Name="Black" CMYK="1 1 0 0" sRGB="0 0 1" />
              <Color Name="Yellow" CMYK="1 1 0 0" sRGB="0 0 1" />
              <Color Name="Magenta" CMYK="1 1 0 0" sRGB="0 0 1" />
              <Color Name="Cyan" CMYK="1 1 0 0" sRGB="0 0 1" />
            </InkZoneProfile>
          </InkZoneProfile>
        </InkZoneProfile>
      </InkZoneProfile>
    </ResourceCmdParams>
  </Command>
</JMF>

When I debug the code, the variable, even after the suggested changes, the var still contains the <ColorPool> node.

Is there an way to do that? All examples I saw around the web and the help I got from here mentioned to use Descendants(CORRECTED: using parent now) since I want to add the node after some root level's descendants.

Thanks in advance.

EDIT1: Code change updated based on Sakura's comment - Resultant XML:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<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" />
              <Color Name="PANTONE 647 C" CMYK="1 1 0 0" sRGB="0 0 255" />
              <Color Name="Black" CMYK="1 1 0 0" sRGB="0 0 255" />
              <Color Name="Yellow" CMYK="1 1 0 0" sRGB="0 0 255" />
              <Color Name="Magenta" CMYK="1 1 0 0" sRGB="0 0 255" />
              <Color Name="Cyan" CMYK="1 1 0 0" sRGB="0 0 255" />
              <InkZoneProfile Separation="Name" ZoneSettingsX="Value" />
              <InkZoneProfile Separation="Name" ZoneSettingsX="Value" />
              <InkZoneProfile Separation="Name" ZoneSettingsX="Value" />
              <InkZoneProfile Separation="Name" ZoneSettingsX="Value" />
              <InkZoneProfile Separation="Name" ZoneSettingsX="Value" />
            </InkZoneProfile>
          </InkZoneProfile>
        </InkZoneProfile>
      </InkZoneProfile>
    </ResourceCmdParams>
  </Command>
</JMF>

Solution

  • You should remove this line:

    var InkZoneProfilePosition = InkZonePath.Parent;
    

    Then change Add to AddFirst. It should be:

        XElement InkZonePath = XmlDoc.Root.Descendants("InkZoneProfile").Where(z => (string)z.Attribute("Side") == "Front").SingleOrDefault();
        //var InkZoneProfilePosition = InkZonePath.Parent;
        if (InkZonePath != null)
        {
            InkZonePath.AddFirst(new XElement("InkZoneProfile",
                        new XAttribute("Separation", "Name"),
                        new XAttribute("ZoneSettingsX", "Value")));
        }