I have a XML file like below:
<report timestamp="3201" reportVersion="2" request="3981135340">
<question timedOut="false" time="3163" attempts="2" correct="true" id="13">
<answer status="attempt">
<radioButton correct="false" value="true" id="17" />
</answer>
<answer status="correct">
<radioButton correct="true" value="true" id="15" />
</answer>
</question>
</report>
I want to read the child nodes based on 'status' attribute of 'answer' node.
Use XmlReader (fastest but forward only), XDocument (LINQ to XML) or XmlDocument. See the examples in the msdn documentation.
Using LINQ to XML:
using System.Xml.Linq;
var doc = XDocument.Parse(xml); // or XDocument.Load()
var elements = from e in doc.Descendants("answer")
where e.Attribute("status").Value == "attempt"
select e;
// elements will be IEnumerable<XElement>
Use XmlDocument and XPath:
XmlDocument document = new XmlDocument();
//here you should load your xml for example with document.Load();
XmlNodeList nodes = document.SelectNodes("/report/question/answer[#status = 'correct']/radioButton");
Just modify the XPath to your needs.
try this one..
foreach (XmlNode xnode in xdoc.SelectNodes("report/question/answer"))
{
if (xnode.Attributes.GetNamedItem("status").Value == "correct")
{
string value = xdoc.SelectSingleNode("report/question/answer[#status='correct']/radioButton").Attributes.GetNamedItem("id").Value;
}
if (xnode.Attributes.GetNamedItem("status").Value == "attempt")
{
string value = xdoc.SelectSingleNode("report/question/answer[#status='attempt']/radioButton").Attributes.GetNamedItem("id").Value;
}
}
Related
I have the following XML in a file called C:\temp\config.xml:
<?xml version="1.0" encoding="utf-8"?>
<dvp:systemConfig xmlns:devop="urn:foo.com:sys:rules">
<dvp:map id="rootFolderMap">
<dvp:entry key="anything" value="folder1"/>
<dvp:entry key="config" value="folder2"/>
<dvp:defaultValue value="folder1" />
</dvp:map>
<dvp:map id="folderMappings">
<dvp:entry key="SYS" value="System" />
<dvp:entry key="OPS" value="Operations" />
<dvp:entry key="DEV" value="Development" />
<dvp:defaultValue value="Miscellaneous" />
</dvp:map>
</dvp:systemConfig>
I am now trying to write C# code that will extract values from this XML. In particular, the list of value properties in the nodes.
List<string> folderNames = new List<string>
XmlDocument doc = new XmlDocument();
doc.Load(#"C:\temp\config.xml");
XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
XmlNodeList xmlNodeList =
doc.SelectNodes("/systemConfig/map[#id='folderMappings']/entry",nsMgr);
foreach (XmlNode xmlNode in xmlNodeList)
{
// I'm hoping xmlNodeList now contains a list of <dvp:entry> nodes.
string folderName = xmlNode.Attributes["value"].ToString().Trim();
folderNames.Add(folderName);
}
However, this code returns an empty xmlNodeList, so the final loop has no items.
I'm not sure how to use the XmlNamespaceManager to pick up the "dvp" prefix, or whether it figures this out when it loads the XmlDocument from the XML on disk.
Can anyone give me some guidance how one goes about using xpath to retrieve values for xml with prefixed nodes? Unfortunately I do not have the power to change the format of the XML so I have to work with the xml I'm provided with.
thanks heaps,
David.
you can ignore the namespace using local-name()
XmlNodeList xmlNodeList =
doc.SelectNodes("/*[local-name()='systemConfig']/*[local-name()='map'][#id='folderMappings']");
I tries to parse a XML file (get it from Dependacy Graph in VS 2012).
Here is sample of my .xml file
<?xml version="1.0" encoding="utf-8"?>
<DirectedGraph xmlns="http://schemas.microsoft.com/vs/2009/dgml">
<Nodes>
<Node Id="#101" Category="CodeSchema_ProjectItem" FilePath="$(ProgramFiles)\windows kits\8.0\include\um\unknwnbase.h" Label="unknwnbase.h" />
<Node Id="#103" Category="CodeSchema_ProjectItem" FilePath="$(ProgramFiles)\windows kits\8.0\include\shared\wtypesbase.h" Label="wtypesbase.h" />
in here, I needs to remove attribute "xmlns" from DirectedGraph.
here's my source to remove this
XmlNodeList rootNode = xmlDoc.GetElementsByTagName("DirectedGraph");
foreach (XmlNode node in rootNode)
{
node.Attributes.RemoveNamedItem("xmlns");
}
but this code doesn't work. If I don't delete this I can't select node like
XmlNodeList nodes = xmlDoc.DocumentElement.SelectNodes("/DirectedGraph/Nodes/Node");
What should I do?
If you like you can work with the namespace instead of removing the declaration:
var xml = #"<?xml version=""1.0"" encoding=""utf-8""?>
<DirectedGraph xmlns=""http://schemas.microsoft.com/vs/2009/dgml"">
<Nodes>
<Node Id=""#101"" Category=""CodeSchema_ProjectItem"" FilePath=""$(ProgramFiles)\windows kits\8.0\include\um\unknwnbase.h"" Label=""unknwnbase.h"" />
<Node Id=""#103"" Category=""CodeSchema_ProjectItem"" FilePath=""$(ProgramFiles)\windows kits\8.0\include\shared\wtypesbase.h"" Label=""wtypesbase.h"" />
</Nodes>
</DirectedGraph>";
var doc = new XmlDocument();
doc.LoadXml(xml);
var manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("d", "http://schemas.microsoft.com/vs/2009/dgml");
var nodes = doc.DocumentElement.SelectNodes("/d:DirectedGraph/d:Nodes/d:Node", manager);
Console.WriteLine(nodes.Count);
Use:
private static XElement RemoveAllNamespaces(XElement xmlDocument)
{
if (!xmlDocument.HasElements)
{
XElement xElement = new XElement(xmlDocument.Name.LocalName);
xElement.Value = xmlDocument.Value;
foreach (XAttribute attribute in xmlDocument.Attributes())
xElement.Add(attribute);
return xElement;
}
return new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(el => RemoveAllNamespaces(el)));
}
Taken from: How to remove all namespaces from XML with C#?.
You might also want to check out: XmlSerializer: remove unnecessary xsi and xsd namespaces.
I don't how to extract the values from XML document, and am looking for some help as I'm new to C#
I am using XmlDocument and then XmlNodeList for fetching the particular XML document
Here is my code
XmlNodeList XMLList = doc.SelectNodes("/response/result/doc");
And my XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<result>
<doc>
<long name="LoadID">494</long>
<long name="EventID">5557</long>
<str name="XMLData"><TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>tblQM2222Components</SubType><IntegerValue title="ComponentID">11111</IntegerValue></str></doc>
<doc>
<long name="LoadID">774</long>
<long name="EventID">5558</long>
<str name="XMLData"><TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>tblQM2222Components</SubType><IntegerValue title="ComponentID">11111</IntegerValue></str></doc>
</result>
</response>
In this i have to fetch every the XMLData data that is under every doc tag and i have to fetch last doc tag EventID.
var xml = XDocument.Parse(xmlString);
var docs = xml.Root.Elements("doc");
var lastDocEventID = docs.Last()
.Elements("long")
.First(l => (string)l.Attribute("name") == "EventID")
.Value;
Console.WriteLine ("Last doc EventId: " +lastDocEventID);
foreach (var doc in docs)
{
Console.WriteLine (doc.Element("str").Element("TransactionDate").Value);
}
prints:
Last doc EventId: 5558
2014-05-28T14:17:31.2186777-06:00
2014-05-28T14:17:31.2186777-06:00
You can use two XPath expressions to select the nodes you want. To answer each part of your question in turn:
To select all of the XMLData nodes:
XmlNodeList XMLList
= doc.SelectNodes("/response/result/doc/str[#name='XMLData']");
To select the last EventId:
XmlNode lastEventIdNode =
doc.SelectSingleNode("/response/result/doc[position() =
last()]/long[#name='EventID']");
If not all doc nodes are guaranteed to have an event id child node, then you can simply:
XmlNodeList eventIdNodes =
doc.SelectNodes("/response/result/doc[long[#name='EventID']]");
XmlNode lastNode = eventIdNodes[eventIdNodes.Count - 1];
That should give you what you've asked for.
Update;
If you want the XML data inside each strXml element, you can use the InnerXml property:
XmlNodeList xmlList
= doc.SelectNodes("/response/result/doc/str[#name='XMLData']");
foreach(XmlNode xmlStrNode in xmlList)
{
string xmlInner = xmlStrNode.InnerXml;
}
There's one result tag short in your xml.
Try using this. It's cleaner too imho
XmlNodeList docs = doc.SelectSingleNode("response").SelectSingleNode("result").SelectNodes("doc");
Then you can use a combination of SelectSingleNode, InnerText, Value to get the data from each XmlNode in your list.
For example if you want the EventID from the first doc tag:
int eventID = int.Parse(docs[0].SelectSingleNode("long[#name='EventID']").InnerText);
This is my two xml document.
This xml is stored in paraouterXml string.
<w:tbl>
<w:tblPr>
</w:tblPr>
<w:tblGrid>
</w:tblGrid>
</w:tbl>
This xml is stored in tblMetaInfo string.
<root>
<w:tblPr>
<w:tblStyle w:val="TableGrid" />
<w:tblW w:w="0" w:type="auto" />
<w:tblLook w:val="04A0" />
</w:tblPr>
<w:tblGrid>
<w:gridCol w:w="1947" />
<w:gridCol w:w="1947" />
</w:tblGrid>
</root>
So,here i want to replace paraouterXml's <w:tblPr>,<w:tblGrid> with tblMetaInfo's <w:tblPr>,<w:tblGrid> elements.
This is c# code...
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(table.OuterXml);
XmlNode newNode = xDoc.DocumentElement;
XmlNodeList tblPrNode = xDoc.GetElementsByTagName("w:tblPr");
tblPrNode[0].RemoveAll();
XmlNodeList tblGridNode = xDoc.GetElementsByTagName("w:tblGrid");
tblGridNode[0].RemoveAll();
XmlDocument xDoc1 = new XmlDocument();
xDoc1.LoadXml(tblMetaInfo);
XmlNode newNode1 = xDoc1.DocumentElement;
XmlNodeList tblPrNode1 = xDoc1.GetElementsByTagName("w:tblPr");
XmlNodeList tblGridNode1 = xDoc1.GetElementsByTagName("w:tblGrid");
tblPrNode[0].ReplaceChild(tblPrNode1[0], tblPrNode[0]);
tblGridNode[0].ReplaceChild(tblGridNode1[0], tblGridNode[0]);
But it throwing some error...
Please guide me to get out of this issue...
ArgumentException: The newChild was created from a different document than the one that created this node.
public XmlNode ReplaceChild(XmlNode newChild, XmlNode oldChild):
If the newChild was created from another document, you can use XmlDocument.ImportNode to import the node to the current document. The imported node can then be passed to the ReplaceChild method.
I have an XML file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<PathMasks>
<Mask desc="Masks_X1">
<config id="01" mask="88" />
<config id="03" mask="80" />
<config id="51" mask="85" />
</Mask>
<Mask desc="Masks_X2">
<config id="70" mask="1" />
<config id="73" mask="6" />
</Mask>
<Types>
<path id="01" desc="TC->PP1" />
<path id="02" desc="TC->PP2" />
<path id="03" desc="TC->PPn" />
</Types>
</PathMasks>
How to parse the file and get all the data of Mask_X1 as following:
id value
=====
01, 88
03, 80
51, 85
The .NET framework I am using is 2.0
As you're working with .Net 2.0 you won't have Linq and will therefore need to use XPath, this sample should help you out.
XmlDocument doc = new XmlDocument();
doc.Load(pathToXmlDoc);
XmlNode node = doc.SelectSingleNode("/PathMasks/Mask[#desc='Masks_X1']");
foreach (XmlNode config in node)
{
Console.WriteLine("{0}\t{1}",
config.Attributes["id"].Value,
config.Attributes["mask"].Value);
}
Using XmlDocument (slower, larger memory footprint, read/write, works the same way XML DOMs everywhere work):
XmlDocument d = new XmlDocument();
d.Load(filename);
string xpath = "/PathMasks/Mask[#desc='Mask_X1']/config"
foreach (XmlElement elm in d.SelectNodes(xpath))
{
Console.WriteLine(elm.GetAttribute("id"), elm.GetAttribute("desc"));
}
Using XPathDocument (faster, smaller memory footprint, read-only, weird API):
XPathDocument d = new XPathDocument(filename);
string xpath = "/PathMasks/Mask[#desc='Mask_X1']/config"
XPathNodeIterator iter = d.CreateNavigator().Select(xpath);
while (iter.MoveNext())
{
Console.WriteLine(iter.Current.GetAttribute("id"), iter.Current.GetAttribute("desc'));
}
I'm sure there's a perfectly good reason why there isn't a method of XPathNavigator that returns an IEnumerable<XPathNavigator> so that you can iterate over the results of an XPath query like a normal person, but I haven't been able to work it out.
Using Linq to XML :
XDocument doc = XDocument.Load(filename);
var query = from mask in doc.Root.Elements("Mask")
where mask.Attribute("desc").Value == "Masks_X1"
from config in mask.Elements("config")
select new
{
id = config.Attribute("id").Value,
value = config.Attribute("mask").Value
};
foreach(var mask in query)
{
Console.WriteLine("{0}\t{1}", mask.id, mask.value);
}
Use XDocument and query into it with Linq to XML
XDocument doc = XDocument.Load("file.xml");
var linqtoxml = from node in document.Descendants("Mask")
where (string)node.Attribute("desc").Value == "Masks_X1"
select node;
foreach (var mask in linqtoxml)
{
// pull data out of here into a structure of your choosing
}