Create dynamic xml using xelement in c# - c#

I want to create xml using XElement as you can see:
XDocument RejectedXmlList = new XDocument
(
new XDeclaration("1.0", "utf-8", null)
);
int RejectCounter = 0;
foreach (Parameter Myparameter in Parameters)
{
if (true)
{
XElement xelement = new XElement(Myparameter.ParameterName, CurrentData.ToString());
RejectedXmlList.Add(xelement);
}
}
As you can see if the condition is OK the parameter should be added to RejectedXmlList but instead I get this exception:
This operation would create an incorrectly structured document.
Of note, the first parameter is added successfully. Only when the second one is added do I get the exception.
The expected result should be like this:
<co>2</co>
<o2>2</o2>
....

You are trying to create an XDocument with multiple root elements, one for each Parameter in Parameters You can't do that because the XML standard disallows it:
There is exactly one element, called the root, or document element, no part of which appears in the content of any other element.
The LINQ to XML API enforces this constraint, throwing the exception you see when you try to add a second root element to the document.
Instead, add a root element, e.g. <Rejectedparameters>, then add your xelement children to it:
// Allocate the XDocument and add an XML declaration.
XDocument RejectedXmlList = new XDocument(new XDeclaration("1.0", "utf-8", null));
// At this point RejectedXmlList.Root is still null, so add a unique root element.
RejectedXmlList.Add(new XElement("Rejectedparameters"));
// Add elements for each Parameter to the root element
foreach (Parameter Myparameter in Parameters)
{
if (true)
{
XElement xelement = new XElement(Myparameter.ParameterName, CurrentData.ToString());
RejectedXmlList.Root.Add(xelement);
}
}
Sample fiddle.

Related

C# How remove single xml parent element node without removing the contents inside the parent node

I am new to C#, kindly help me. How to remove the single xml element node 'PaymentRecord' and content inside that should not get deleted.
<Payments>
<PaymentRecord>
<PayId>2031</PayId>
<Reference>Policy03</Reference>
<StatusCode>ACV</StatusCode>
<MethodDetail>
<PaymentMethodDetail>
<CardPaymentDetails>
<CardHolderName>abcded</CardHolderName>
<CardTransactionDetails>
<StoredCard>N</StoredCard>
</CardTransactionDetails>
</CardPaymentDetails>
</PaymentMethodDetail>
</MethodDetail>
<CurrencyCode>USD</CurrencyCode>
</PaymentRecord>
</Payments>
I need to remove "PaymentRecord" element from the XML. I need like below
<Payments>
<PayId>2031</PayId>
<Reference>Policy03</Reference>
<StatusCode>ACV</StatusCode>
<MethodDetail>
<PaymentMethodDetail>
<CardPaymentDetails>
<CardHolderName>abcded</CardHolderName>
<CardTransactionDetails>
<StoredCard>N</StoredCard>
</CardTransactionDetails>
</CardPaymentDetails>
</PaymentMethodDetail>
</MethodDetail>
<CurrencyCode>USD</CurrencyCode>
</Payments>
I have tried my below code, but its deleting the complete node which I don't want to do :- here 'queuePayload' is the xml element
XmlNodeList payloadRecordList = queuePayload.SelectNodes("//Payments/PaymentRecord");
foreach (XmlElement singleNode in payloadRecordList)
{
XmlHelper.removeElem((XmlElement)singleNode.ParentNode, "//PaymentRecord");
XmlDocument xmlDoc = singleNode.OuterXml;
// my remaining logic goes based on "xmldoc" value - I will inserting this data to table
}
You can use System.Xml.Linq with its XDocument to achiev this. Load the input and create a new document out of it like:
XDocument inputDoc = XDocument.Load(inputFile, LoadOptions.None);
XDocument outputDoc = new XDocument();
var elements = inputDoc.Element("Payments").Elements().Select(pr => pr.Elements());
XElement newElement = new XElement("Payments");
foreach (var element in elements)
{
newElement.Add(element);
}
outputDoc.Add(newElement);
Console.WriteLine(outputDoc.ToString());
I think #Fructzwerg is slightly overcomplicating it.
You can remove the PaymentRecord node and add all its children to the root in one go.
var xDoc = XDocument.Load(filePath);
var paymentRecord = xDoc.Root.Element("PaymentRecord");
var nodes = xDoc.Root.Element("PaymentRecord").Elements();
paymentRecord.Remove();
xDoc.Root.Add(nodes);
Console.WriteLine(xDoc.ToString());
dotnetfiddle

XElement.Root.Element keeps returning null

I am learning C# and trying to flatten XML following this code from this post
var doc = XDocument.Load("test.xml");
XNamespace ns = "mynamespace";
var member = doc.Root.Element(ns + "member");
// This will *sort* of flatten, but create copies...
var descendants = member.Descendants().ToList();
// So we need to strip child elements from everywhere...
// (but only elements, not text nodes). The ToList() call
// materializes the query, so we're not removing while we're iterating.
foreach (var nested in descendants.Elements().ToList())
{
nested.Remove();
}
member.ReplaceNodes(descendants);
This is my XML (sorry I don't know how to post fancy code style)
<ApplicationExtraction>
<IsCurrent>Yes</IsCurrent>
<ApplicationDate>10/06/2015</ApplicationDate>
<Status>Application Received</Status>
<EquipmentType>Equipment</EquipmentType>
<IsLoan>No</IsLoan>
</ApplicationExtraction>
There is namespace so I changed var member = doc.Root.Element(ns + "member"); to var member = doc.Root.Element("ApplicationExtraction"); but this returns NULL.
I also try XElement sRoot = doc.Root.Element("ApplicationExtraction"); from this post I still get the same result.
I read up Microsoft XElement document but don't see how I can fix this.
What could I have done wrong?
XElement sRoot = doc.Root.Element("ApplicationExtraction");
will look for an element 'ApplicationExtraction' inside the Root.
If you want the Root, just reference
doc.Root
In your XML, doc.Root is the root node i.e. ApplicationExtraction and there is no node ApplicationExtraction inside the root node thus you are getting null.
To fetch any specific node you need(for example):-
XElement member = doc.Root.Element("IsCurrent");
and to fetch the value inside the node:-
string member = (string)doc.Root.Element("IsCurrent");

Need a simple way to check if XElement exist before creating it in xml file

I need to check if an XElement exists in the xml file. The code below throws an exception so I don't know yet how to solve it.
XDocument doc1 = XDocument.Load(#filePath);
XElement arrivalInstructions = doc1.Descendants("arrivalInstructions").First();
if (arrivalInstructions == null)
{ here I would put the code to create the XElement but it never gets here }
I've also tried this but didn't work either
XElement xml = XElement.Load(#filePath);
XElement configuration = xml.Element("Root");
var xxx = configuration.Element("arrivalInstructions");
if (xxx == null)
{ here I would put the code to create the XElement but it never gets here }
Use FirstOrDefault instead of First.It doesn't throw exception if there is no item, it just returns null.

LINQ Create new Xdocument by looping through existing XML file

I'm very new to LINQ so please bear with me :)
I'm currently trying to reverse engineer a SSIS package (.dtsx) which is in XML format into a .BIML file which is also XML based. However they have different constructs for the same objects.
So what i'm trying to do is to loop through the XML of the .dtsx package and have a basically check the type of the element and create an equivalent element in a new file but with a different name/attributes, however i will need to keep the hierarchical relationship of the objects as i create the elements in the new file.
But i'm really struggling with how i can add new elements to the new file whilst i'm looping through the source file.
Is anyone able to offer some pointers?
I'm able to loop through the file at the moment (i'm just outputting to a console window at teh moment to check understand if i'm looping corectly) but i'm struggling to add the elements into the new file
any help very much appreciated
string file = #"F:\\sample.dtsx"
XDocument xDoc = XDocument.Load(file);
XNamespace env = "www.microsoft.com/SqlServer/Dts";
IEnumerable<XElement> elements = xDoc.Root.Descendants(); //
XDocument BIMLXdoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("Root"));
//BIMLXdoc.Add(new XElement("test")); ####This doesn't work
foreach (XElement element in elements)
{
// Test element and if of the correct type add new elemnt to biml file
IEnumerable<XAttribute> attribs = element.Attributes();
foreach (XAttribute attrib in attribs)
{
Console.WriteLine(element.Name.LocalName + " - Attribute(" + attrib.Name.LocalName + ") - Value:(" + attrib.Value + ")");
}
}
BIMLXdoc.Save("F:\\BIMLTest.xml");
In commented line you are trying to add node to the top level. Correct XML document has only one root element. So, add your nodes to Root element:
var BIMLXdoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("Root"));
BIMLXdoc.Root.Add(new XElement("test")); // This works
If you want to add a new Element to your Xdoc, you need to add it in a specific place:
Change:
BIMLXdoc.Add(new XElement("test"));
To:
BIMLXdoc.Element("Root").Add(new XElement("TestChild", "TestChildValue"));
And you will have a child element.

How do I add a document type to an XDocument?

I have an existing XDocument object that I would like to add an XML doctype to. For example:
XDocument doc = XDocument.Parse("<a>test</a>");
I can create an XDocumentType using:
XDocumentType doctype = new XDocumentType("a", "-//TEST//", "test.dtd", "");
But how do I apply that to the existing XDocument?
You can add an XDocumentType to an existing XDocument, but it must be the first element added. The documentation surrounding this is vague.
Thanks to Jeroen for pointing out the convenient approach of using AddFirst in the comments. This approach allows you to write the following code, which shows how to add the XDocumentType after the XDocument already has elements:
var doc = XDocument.Parse("<a>test</a>");
var doctype = new XDocumentType("a", "-//TEST//", "test.dtd", "");
doc.AddFirst(doctype);
Alternately, you could use the Add method to add an XDocumentType to an existing XDocument, but the caveat is that no other element should exist since it has to be first.
XDocument xDocument = new XDocument();
XDocumentType documentType = new XDocumentType("Books", null, "Books.dtd", null);
xDocument.Add(documentType);
On the other hand, the following is invalid and would result in an InvalidOperationException: "This operation would create an incorrectly structured document."
xDocument.Add(new XElement("Books"));
xDocument.Add(documentType); // invalid, element added before doctype
Just pass it to the XDocument constructor (full example):
XDocument doc = new XDocument(
new XDocumentType("a", "-//TEST//", "test.dtd", ""),
new XElement("a", "test")
);
or use XDocument.Add (the XDocumentType has to be added before the root element):
XDocument doc = new XDocument();
doc.Add(new XDocumentType("a", "-//TEST//", "test.dtd", ""));
doc.Add(XElement.Parse("<a>test</a>"));

Categories