EnsureLocalDisposalRule for XmlNodeList - c#

When I run Gendarme 2.11 on my C#.NET project the following code triggers the EnsureLocalDisposalRule:
XmlDocument myXmlDoc = this.GetXmlDoc();
foreach (XmlNode myNode in myXmlDoc.GetElementsByTagName("TAGNAME"))
{
... does something with myNode ...
}
with the message:
Local of type 'XmlNodeList' is not disposed of (at least not locally).
After reading the rule description
I attempted to rewrite it as follows:
XmlDocument myXmlDoc = this.GetXmlDoc();
using (XmlNodeList myNodeList = myXmlDoc.GetElementsByTagName("TAGNAME"))
{
foreach (XmlNode myNode in myNodeList )
{
... does something with myNode ...
}
}
but this gives the error:
'System.Xml.XmlNodeList': type used in a using statement must be
implicitly convertible to 'System.IDisposable'
What is causing this? Is this a bug in Gendarme? Or have I misunderstood the rule? How could my code be improved?

Related

Failing to read value XML attribute in C#

I am trying to read a file produced by another developer. The file looks something like this. I am trying to read in the value for 'ProfileName', but when I look at the object in memory, I see null for the Value (capital V) attribute. The only place I can see the string "GolfLeague-Dual" is in the outerxml attribute, but I would have to parse through a bunch of just to get it.
<?xml version="1.0"?>
<TopNode>
<ProfileSettings>
<ProfileName value="GolfLeague-Dual" />
</ProfileSettings>
</TopNode>
Here is my code to try to read this:
XmlDocument doc = new XmlDocument();
doc.Load(directory + #"\Settings.xml");
XmlElement root = doc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("//ProfileSettings");
foreach (XmlNode node in nodes) {
Console.WriteLine(node["ProfileName"].Value);
}
Your code is trying to get the inner value of the node, not an attribute called value. Try this instead...
foreach (XmlNode node in nodes) {
Console.WriteLine(node["ProfileName"].Attributes["value"].Value);
}
Here's a working dotnetfiddle...
https://dotnetfiddle.net/pmJKbX

Why is my xml doc considered an element?

I am trying to load an xml file into an xmlDocument but receive an error that it cannot cast the xmlelement to a xmldocument why?
XML
<VR>
<SubscriberID>xxxx</SubscriberID>
<EmailAddress>m#gmail.com</EmailAddress>
<FirstName>m</FirstName>
<LastName>x</LastName>
<State>CO</State>
<Country/>
<BirthDate>11/16/3004</BirthDate>
<SendEmail>False</SendEmail>
<Preference Value="true" Key="life"/>
<Preference Value="true" Key="yo"/>
</VR>
C# Test
preferenceHelper target = new preferenceHelper(); // TODO: Initialize to an appropriate value
XmlDocument docIn = new XmlDocument();
docIn.Load(#"C:/INTG/trunk/src/VRI.Integration.Email/Test/xmlIn.xml");
XmlDocument expected = null; // I know this will fail in the test, but it should compile, right?
XmlDocument actual;
actual = target.preferencesXmlDoc(docIn);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
C# function:
public class preferenceHelper
{
public preferenceHelper() { }
XmlDocument docOut = new XmlDocument();
public XmlDocument preferencesXmlDoc(XmlDocument docIn)
{
foreach (XmlDocument root in docIn.SelectNodes("//VR"))
{
foreach (XmlDocument node in root.SelectNodes("//Preference"))
{
XmlNode Name = docIn.CreateElement("Name");
Name.InnerText = node.InnerText = node.Attributes["Key"].Value;
XmlNode Value = docIn.CreateElement("Value");
Value.InnerText = node.InnerText = node.Attributes["Value"].Value;
docOut.CreateElement("Property").AppendChild(Name).AppendChild(Value);
}
}
return docOut;
}
}
Error
Test method Test.preferenceHelperTest.preferencesXmlDocTest threw exception:
System.InvalidCastException: Unable to cast object of type 'System.Xml.XmlElement' to type 'System.Xml.XmlDocument'.
I will not be adding a namespace to the xmlIn, if this is required - how might I load in my xml File?
Where it fails: actual = target.preferencesXmlDoc(docIn);
Thanks
Your problems are in these statements:
foreach (XmlDocument root in SelectNodes(...))
foreach implicitly casts each value in the sequence to the type you specify. The statement is expanded to:
using(var e = sequence.GetEnumerator())
{
while (e.MoveNext())
{
XmlDocument v = (XmlDocument)e.Current;
// loop body
}
}
The reason this is crashing with an InvalidCastException is that the type of node you're selecting is XmlElement, not XmlDocument. To fix the issue, simply switch the type in your foreach statement to XmlElement.
You can also improve readability by using XPath to reach the Preference elements, replacing both loops with a single:
foreach (XmlElement node in docIn.SelectNodes("/VR/Preference"))
Your outer SelectNodes loop is actually completely redundant because //Preference will get all Preference descendants from the root of the document already, not just from that specific child VR.
The proplem is here:
foreach (XmlDocument root in docIn.SelectNodes("//VR"))
and here:
foreach (XmlDocument node in root.SelectNodes("//Preference"))
XmlNode.SelectNodes() returns an XmlNodeList, which is an IEnumerable of XmlNodes. It will not contain any XmlDocuments.
So do this:
foreach (XmlNode root in docIn.SelectNodes("//VR"))
and this:
foreach (XmlElement node in root.SelectNodes("//Preference"))
XmlDocument.SelectNodes("//VR") returns an XmlNodeList, not an XmlDocument. So at the least you need to change your code to:
public XmlDocument preferencesXmlDoc(XmlDocument docIn)
{
foreach (XmlNode root in docIn.SelectNodes("//VR"))
{
foreach (XmlNode node in root.SelectNodes("//Preference"))
{
A document usually has a header:
<?xml version="1.0"?>
Without the header it is considered an element.
Try adding one.

Exception occuring while extracting the value of the node in xdocument

I have an xml like :
<RunResult>
<PreviewRecords></PreviewRecords>
<RecordsProcessed>100</RecordsProcessed>
<LogError>false</LogError>
</RunResult>
I am using the following command to fetch the value of the node RecordsProcessed ,
int NofRecords = 0;
NofRecords = Convert.ToInt32(xdRunResultDoc.Root.Element("RunResult").Element("RecordsProcessed").Value;
But at this line it is throwing exception " object reference not set to an instance of an object".
Please suggest where I am going wrong.
xdRunResultDoc.Root already points to <RunRdesult> element, so you don't have to call Element("RunResult") again.
And I suggest using (int) casting on XElement instead of Convert.ToInt32: XElement Explicit Conversion (XElement to Int32)
int NofRecords = (int)xdRunResultDoc.Root.Element("RecordsProcessed");
Try this
int NofRcord = Convert.ToInt32(xdRunResultDoc.Root.Element("RecordsProcessed").Value);
See this link for more details http://msdn.microsoft.com/en-us/library/bb675196.aspx
this works for me:
string xmlstring = #"<?xml version='1.0' encoding='utf-8'?>
<RunResult>
<PreviewRecords></PreviewRecords>
<RecordsProcessed>100</RecordsProcessed>
<LogError>false</LogError>
</RunResult>";
System.Xml.Linq.XDocument doc = XDocument.Parse(xmlstring);
int NofRecords = 0;
NofRecords = Convert.ToInt32(doc.Element("RunResult").Element("RecordsProcessed").Value);
You can Find the solution by your self, Why don't you debug and see which causing "object reference not set to an instance of an object" error?
You can add watch to xdRunResultDoc and in the run time you can check what is root node and what you get for xdRunResultDoc.Root.Element("RunResult") etc..
Here your root node is RunResult you can't find Elements inside root node called RunResult
You better check this code project tutorial.
Try this code
read entire text from the xml file and load that to a XmlDocument
XmlNode rootNode = xDoc.SelectSingleNode("RunResult");
if (rootNode.HasChildNodes)
{
foreach (XmlNode node in rootNode.ChildNodes)
{
if (node.Name =="RecordsProcessed")
{
NofRecords=Convert.ToInt32(node.InnerText);
}
}
}

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.

XmlNode.ReplaceChild is complaining that the node I'm trying to remove is not a child despite the fact that I got to the node via ParentNode

I have a simple function that's designed to copy a section of an xml document to another. I want to replace one node with the other so ReplaceChild seems like the logical choice. I keep getting the error 'The reference node is not a child of this node.' though. That seems odd since I found that node by asking for the parent in the first place. Any idea what I'm doing wrong?
private static void KeepSection(XmlDocument newDoc, XmlDocument currentDoc, XmlNamespaceManager nsmgr, string path)
{
XmlNode section = currentDoc.SelectSingleNode(path, nsmgr);
XmlNode newSection = newDoc.SelectSingleNode(path, nsmgr);
if (newSection != null && section != null)
{
XmlNode parent = newSection.ParentNode;
parent.ReplaceChild(newSection, newDoc.ImportNode(section, true));
}
}
It looks like you have your ReplaceChild parameters reversed:
public virtual XmlNode ReplaceChild(
XmlNode newChild,
XmlNode oldChild
)
Actually I was being an idiot. I got the parameters to ReplaceChild the wrong way around. The code should have been,
parent.ReplaceChild(newDoc.ImportNode(section, true), newSection);
Sorry about that!

Categories

Resources