Adding child node inside a XML node using C# - c#

Here is my given XML:-
<?xml version="1.0" encoding="utf-8"?>
<Processes>
<Process Name="Process1" Namespace="" Methodname="">
<Validations/>
<Transformations/>
<Routings/>
</Process>
</Processes>
I want to add new node Validation inside Validations and for that i have written the following code:-
XmlDocument originalXml = new XmlDocument();
originalXml.Load(#"C:\Users\Sid\Desktop\Process\Process1.xml");
XmlNode Validations = originalXml.SelectSingleNode("/Processes/Process[Name="Process1"]/Validations");
XmlNode Validation = originalXml.CreateNode(XmlNodeType.Element, "Validation",null);
Validation.InnerText = "This is my new Node";
Validations.AppendChild(Validation);
originalXml.Save(#"C:\Users\Sid\Desktop\Process\Process1.xml");
But, I am getting error in the line "Validations.AppendChild(validation)" as Object reference not set to an instance of an object. Please suggest some way to fix it.

You can do by this
XDocument doc = XDocument.Load(#"C:\Users\Sid\Desktop\Process\Process1.xml");
var a = doc.Descendants("Validations").FirstOrDefault();
a.Add(new XElement("Validation", "This is my new Node"));
doc.Save(#"C:\Users\Sid\Desktop\Process\Process1.xml");

Your SelectSingleNode() didn't match any element, hence the null-reference exception. Beside the conflicting double-quotes problem, you should use #attribute_name pattern to reference attribute using XPath. So the correct expression would be :
originalXml.SelectSingleNode("/Processes/Process[#Name='Process1']/Validations");

Related

Accessing the xml tag with C# and updating the content

I have an xml file that I converted from pdf to xml.
Example XML looks as follows
<?xml version="1.0" encoding="UTF-8"?>
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.graphics">
<office:body>
<office:drawing>
<draw:page draw:name="page1" draw:style-name="dp2" draw:master-page-name="master-page3">
<draw:frame draw:style-name="gr9" draw:text-style-name="P10" draw:layer="layout" svg:width="1.242cm" svg:height="0.357cm" svg:x="17.055cm" svg:y="11.787cm">
<draw:text-box>
<text:p text:style-name="P2"><text:span text:style-name="T6">Example</text:span></text:p>
</draw:text-box>
</draw:frame>
</draw:page>
</office:drawing>
</office:body>
</office:document>
The C# code I'm trying to use:
XmlDocument doc = new XmlDocument();
XmlNamespaceManager namespaces = new XmlNamespaceManager(doc.NameTable);
namespaces.AddNamespace("xmlns:draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");
doc.Load("invoiceto.xml");
doc.SelectSingleNode("/draw:frame/draw:text-box/text:p/text:span", namespaces).InnerText = "new value";
I get this error
'' text 'namespace prefix not defined.'
I want to replace the text of example with C# but how can I get to the <text: span text: style-name = "T6"> tag with C#?
First of all the prefix added to XmlNamespaceManager shouldn't include the xmlns part. Then you also need to add the prefix text besides draw because both will be used in the XPath expression for calling SelectSingleNode. Last, since the element <draw:frame> isn't the root element you need to either specify full path starting from the root or start the XPath using // (the descendant-or-self axis) instead:
XmlNamespaceManager namespaces = new XmlNamespaceManager(doc.NameTable);
namespaces.AddNamespace("draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");
namespaces.AddNamespace("text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0");
doc.SelectSingleNode("//draw:frame/draw:text-box/text:p/text:span", namespaces).InnerText = "new value";
dotnetfiddle demo

Unable to use XmlDocument.SelectSingleNode on XML with Two Namespaces

I'm trying to parse the following XML:
<?xml version="1.0" encoding="utf-8"?>
<A2AAnf:MPPPPPP xsi:schemaLocation="urn:A2AAnf:xsd:$MPPPPPP.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:A2AAnf="urn:A2AAnf:xsd:$MPPPPPP">
<A2AAnf:Num>0</A2AAnf:Num>
<A2AAnf:FIT xmlns="urn:iso:std:iso:20022:xsd:003.001">
<Hdr>
<Inf>
<Mtd>TEST</Mtd>
</Inf>
</Hdr>
</A2AAnf:FIT>
I want to access the <Mtd> tag.
XMLQuire shows the path to be /A2AAnf:MPPPPPP/A2AAnf:FIT/dft:Hdr/dft:Inf/dft:Mtd, but when I'm trying to parse it using the following code:
XmlDocument xmldocument = new XmlDocument();
var xmlNameSpaceManager = new XmlNamespaceManager(xmldocument.NameTable);
xmlNameSpaceManager.AddNamespace("A2AAnf", "urn:A2AAnf:xsd:$MPPPPPP");
try
{
xmldocument.LoadXml(m_XML);
var node = xmldocument.SelectSingleNode("/A2AAnf:MPPPPPP/A2AAnf:FIT/dft:Hdr/dft:Inf/dft:Mtd", xmlNameSpaceManager);
}
I receive the following error:
namespace prefix 'dft' is not defined
And since I can't find "dft" in my XML, I also tried to remove the "dft" prefix and search for the same string without "dft". This time, nothing was returned.
What am I missing?
You have to add dft to your XmlNamespaceManager:
var xmlNameSpaceManager = new XmlNamespaceManager(xmldocument.NameTable);
xmlNameSpaceManager.AddNamespace("A2AAnf", "urn:A2AAnf:xsd:$MPPPPPP");
xmlNameSpaceManager.AddNamespace("dft", "urn:iso:std:iso:20022:xsd:003.001");
The prefixes you use in your XPath query have nothing to do with the prefixes used in the XML document. They are instead the prefixes you define in your XmlNamespaceManager.

How to get child and grandchild elements from XML element?

So, I have an XElement, that contains multiple child elements. I can successfully declare the XElement, and write it to a file:
Test.project:
<?xml version="1.0" encoding="utf-8"?>
<project>
<child>
<grand-child1>
<great-grand-child1>Hello There!</great-grand-child1>
<great-grand-child2>Hello World!</great-grand-child2>
</grand-child1>
<grand-child2>Testing 123...</grand-child2>
</child>
</project>
Then I'm trying to read from the file. I searched for ways to get child and grand-child nodes, and found I can use XElement.XPathSelectElement(). The problem is, Visual C# doesn't recognize XPathSelectElement as a method for an XElement. I've searched for usage examples for the method, and they all say to use XElement.XPathSelectElement.
For example, I tried:
x_el = new XElement("project",
new XElement("child",
new XElement("grand-child", "Hello World!")
);
string get_string = x_el.XPathSelectElement("child/grand-child");
...but XPathSelectElement is not recognized. What am I doing wrong?
You need to add System.Xml.XPath namespace as well
like
using System.Xml.XPath;
after that try below
x_el = new XElement("project",
new XElement("child",
new XElement("grand-child", "Hello World!")
));
// XPathSelectElement method return XElement not string , use var or XElement
XElement element = x_el.XPathSelectElement("child/grand-child");
string get_string = element.ToString()
Or
var get_string = x_el.XPathSelectElement("child/grand-child").ToString();

Xpath for element with colon in element name

my xml is
<?xml version="1.0" encoding="utf-8"?>
<EntityDescriptor ID="_2d6175bd-f939-49f2-a980-db4179f32074" entityID="https://server1.domain.com:xx3/yyy/" xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
<RoleDescriptor xsi:type="fed:ApplicationServiceType" xmlns:fed="http://docs.oasis-open.org/wsfed/federation/200706" protocolSupportEnumeration="http://docs.oasis-open.org/wsfed/federation/200706" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<fed:ClaimTypesRequested>
<auth:ClaimType Uri="http://schemas.microsoft.com/ws/2008/06/identity" Optional="true" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706" />
</fed:ClaimTypesRequested>
<fed:TargetScopes>
<EndpointReference xmlns="http://www.w3.org/2005/08/addressing">
<Address>https://baarnntl1/</Address>
</EndpointReference>
</fed:TargetScopes>
<fed:PassiveRequestorEndpoint>
<EndpointReference xmlns="http://www.w3.org/2005/08/addressing">
<Address>https://baarnntl1/</Address>
</EndpointReference>
</fed:PassiveRequestorEndpoint>
</RoleDescriptor>
</EntityDescriptor>
I want to change the address element value
XmlDocument fedMetaDocument = new XmlDocument();
fedMetaDocument.Load(federatedMetadataFile);
XmlNamespaceManager mgr = new XmlNamespaceManager(fedMetaDocument.NameTable);
mgr.AddNamespace("fed", "http://docs.oasis-open.org/wsfed/federation/200706");
foreach (XmlNode targetScopeNode in fedMetaDocument.SelectNodes("TargetScopes/EndpointReference/Address", mgr))
{
targetScopeNode.Value = tsakListUrl;
}
foreach (XmlNode PassiveRequestorEndpointNode in fedMetaDocument.SelectNodes("TargetScopes/EndpointReference/Address", mgr))
{
PassiveRequestorEndpointNode.Value = tsakListUrl;
}
I am getting an error
System.Xml.XPath.XPathException was unhandled by user code
Message=Expression must evaluate to a node-set.
Source=System.Xml
StackTrace:
at MS.Internal.Xml.XPath.XPathParser.ParseNodeTest(AstNode qyInput, AxisType axisType, XPathNodeType nodeType)
at MS.Internal.Xml.XPath.XPathParser.ParseStep(AstNode qyInput)
at MS.Internal.Xml.XPath.XPathParser.ParseRelativeLocationPath(AstNode qyInput)
Your XPath expression should contain the namespace when selecting a node with a namespace applied. [Reference]
So the XPath expressions should be the following
//fed:TargetScope/EndpointReference/Address
instead of
//TargetScope/EndpointReference/Address
Maybe this helps...try code below:
foreach (XmlNode targetScopeNode in fedMetaDocument.GetElementsByTagName("Address"))
{
targetScopeNode.InnerText = tsakListUrl;
}
In addition to
mgr.AddNamespace("fed", "http://docs.oasis-open.org/wsfed/federation/200706");
you need to declare a prefix for the default namespace:
mgr.AddNamespace("meta", "urn:oasis:names:tc:SAML:2.0:metadata");
And then use it on all elements that are in that namespace:
fedMetaDocument.SelectNodes("fed:TargetScopes/meta:EndpointReference/meta:Address", mgr))
Namespaces are one of those things that, if you don't understand the fundamentals, will really trip you up if you try to just get them to work by trial and error. See this earlier answer of mine about the default namespace and XPath.

Inserting XML Fragment after last specific node/element

I want to add an XML fragment to the last element to an XML document and I having problems i.e. the error I get is:
"The reference node is not a child of
this node".
So my existing XML document looks like this:
<MAP>
<LAYER name ="My first Layer">
<DATASET name="foo dataset" />
<SYMBOLOGY>
<SYMBOL colour="red" />
</SYMBOLOGY>
</LAYER>
<LAYER name="My second Layer">
<DATASET name="bar dataset" />
<SYMBOLOGY>
<SYMBOL colour="blue" />
</SYMBOLOGY>
</LAYER>
</MAP>
The XML fragment I want to insert after the last LAYER element is:
<LAYER name="My third Layer">
<DATASET name="whatever dataset" />
<SYMBOLOGY>
<SYMBOL colour="yellow" />
</SYMBOLOGY>
</LAYER>
The code I am using is:
XmlDocumentFragment xmlDocFrag = xmlDocument.CreateDocumentFragment();
xmlDocFrag.InnerXml = inputXML; //which is basically the third layer example - see above.
XmlElement rootElement = xmlDocument.DocumentElement;
XmlNode lastLayerNode = rootElement.SelectSingleNode(#"//LAYER[last()]");
rootElement.InsertAfter(xmlDocFrag, lastLayerNode); //error raised here.
Any ideas on what I'm doing wrong here would be much appreciated. My XPath query seems find and it seems to select the correct last layer it just won't insert after it for some bizarre reason.
UPDATE/SOLUTION - How to do this with XPATH
Finally figured it out in XPath - see the code below, I think it was down to basically not selecting the correct parent node in the first place, it's incorrect to select the last LAYER then try and InsertAfter() on this node. Better to select the level above i.e. MAP then AppendChild(). See below:
XmlDocumentFragment xmlDocFrag = xmlDocument.CreateDocumentFragment();
xmlDocFrag.InnerXml = inputXML;
XmlElement mapElement = (XmlElement)xmlDocument.SelectSingleNode(#"//MAP[last()]");
mapElement.AppendChild(xmlDocFrag);
Thanks to all the replies and help too :)
Taking into consideration that you need this to work with Framework 2.0, here's another solution:
string xml = "<map><layer>1</layer><layer>2</layer></map>";
string addMe = "<layer>3</layer>";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xml);
XmlDocumentFragment xmlDocFrag = xmlDocument.CreateDocumentFragment();
xmlDocFrag.InnerXml = addMe;
XmlElement rootElement = xmlDocument.DocumentElement;
rootElement.AppendChild(xmlDocFrag);
This results in:
<map><layer>1</layer><layer>2</layer><layer>3</layer></map>
Things look pretty good, but I would first try to avoid the xpath selection for the last node, and instead just use this:
rootElement.InsertAfter(xmlDocFrag, rootElement.LastChild);
I had similar issue, I used the ImportNode method to solve it
Here is a small example how you can use it to add node from different xml (stored in string) to your example at desired node in xml tree
string xmlstring =#"<tag>.....</tag>"; // holds xml tree to be appended
XmlDocument xml2 = new XmlDocument();
xml2.Load(#"path_of_main_xml");
XmlDocument xml1 = new XmlDocument();
xml1.Load(new StringReader(xmlString));
// get the node you want to import which in this icase is string
XmlNode elem = xml1.DocumentElement;
// use importNode to import it
XmlNode impnode = xml2.ImportNode(elem,true);
// get the node list of all node of particular tag name
XmlNodeList eNode = xml2.GetElementsByTagName("tag_name_of_parent");
eNode[0].AppendChild(impnode); // append new node
// write back the updates to same file
XmlWriter writer = XmlWriter.Create(#"path_of_main_xml");
xml2.Save(writer);

Categories

Resources