Retrieve child node value - c#

here is the XML i am using
there are multiple instances of LineItemDetails i posted only one of it ...
<LineItemDetail>
<DetailNumber>1</DetailNumber>
<LineItemNumber>1</LineItemNumber>
<BatchSequenceNumber>1</BatchSequenceNumber>
<RecordSequenceWithinBatch>1</RecordSequenceWithinBatch>
<ChargeAmount Name="GrossBilled">365.380</ChargeAmount>
<Tax>
<TaxType>Tax</TaxType>
<TaxAmount Name="Billed">15.630</TaxAmount>
<TaxBreakdown>
<TaxCode>MN</TaxCode>
<TaxAmount Name="Billed">15.630</TaxAmount>
</TaxBreakdown>
</Tax>
<AddOnCharges>
<AddOnChargeName>ISCAllowed</AddOnChargeName>
<AddOnChargePercentage>-9</AddOnChargePercentage>
<AddOnChargeAmount>-32.880</AddOnChargeAmount>
</AddOnCharges>
<TotalNetAmount>348.130</TotalNetAmount>
<CouponDetails>
<TicketOrFIMIssuingAirline>160</TicketOrFIMIssuingAirline>
<TicketOrFIMCouponNumber>1</TicketOrFIMCouponNumber>
<TicketDocOrFIMNumber>2649488544</TicketDocOrFIMNumber>
<CheckDigit>6</CheckDigit>
<CurrAdjustmentIndicator>USD</CurrAdjustmentIndicator>
<ElectronicTicketIndicator>E</ElectronicTicketIndicator>
<AirlineFlightDesignator>MR</AirlineFlightDesignator>
<FlightNo>885</FlightNo>
<FlightDate>2013-04-03</FlightDate>
<FromAirportCode>ULN</FromAirportCode>
<ToAirportCode>HKG</ToAirportCode>
<SettlementAuthorizationCode>861FBKOPVEZZ4</SettlementAuthorizationCode>
<Attachment>
<AttachmentIndicatorOriginal>N</AttachmentIndicatorOriginal>
</Attachment>
</CouponDetails>
</LineItemDetail>
The above is the XML doc.
i need to retrieve the value of the tag <TaxCode>.
Till now i got this far
var tax = from d in doc.Root.Descendants("Tax") select d;
foreach (var p in tax)
{
taxcode= p.Element("TaxCOde").Value;
}

p.Element("TaxCOde") checks only direct children of p (<Tax> element), so it finds nothing.
Try that:
foreach (var p in tax)
{
taxcode= (string)p.Element("TaxBreakdown").Element("TaxCode");
}
I used (string)XElement conversion instead of XElement.Value property, because it will not throw NullReferenceException when element is not found.
Edit
Test code for your sample XML:
var doc = XDocument.Load("source.txt");
var lineItemDetails = doc.Descendants("LineItemDetail");
foreach (var lineItemDetail in lineItemDetails)
{
var tax = lineItemDetail.Element("Tax");
var taxCode = (string)tax.Element("TaxBreakdown").Element("TaxCode");
}
taxCode is MN.

XDocument DocumentObject = XDocument.Load(yourxml);
IEnumerable<XElement> Tax= from TaxInfo in DocumentObject.Descendants("Tax") select TaxInfo;
foreach (var t in Tax)
{
TaxType = (string)t.Element("TaxType");
}

Try this
foreach (var p in tax)
{
taxcode= p.Element("TaxBreakdown").Element("TaxCode").Value;
}

Why don't you try to use an XmlDocument? one you've loaded the xml in the document you could do this (I've declared the XmlDocument as doc):
foreach(XmlElement elem in doc.GetElementsByTagName("TaxCOde"))
taxcode = elem.InnerText;
I've written this using only my memory, so I'm sorry if I've made some grammar or syntax mistakes

Related

how can i get node Element value From LINQ?

i have a collection of service users, i want to iterate over ServiceUsers and extract value from ServiceUser, (ID, USER_NAME, UN_ID, IP, NAME)
<ServiceUsers xmlns="">
<ServiceUser>
<ID>280334</ID>
<USER_NAME>YVELAMGAMOIYENET12:206322102</USER_NAME>
<UN_ID>731937</UN_ID>
<IP>91.151.136.178</IP>
<NAME>?????????????????????: 123456</NAME>
</ServiceUser>
<ServiceUser>
<ID>266070</ID>
<USER_NAME>ACHIBALANCE:206322102</USER_NAME>
<UN_ID>731937</UN_ID>
<IP>185.139.56.37</IP>
<NAME>123456</NAME>
</ServiceUser>
</ServiceUsers>
my Code looks like this, but i am getting null point exception.
XDocument doc = XDocument.Parse(xml)
List<XElement> xElementList = doc.Element("ServiceUsers").Descendants().ToList();
foreach (XElement element in xElementList)
{
string TEST= element.Element("Name").Value;
comboBoxServiceUser.Items.Add(element.Element("Name").Value);
}
I used the example from XmlSerializer.Deserialize Method as the base for the following snippet that reads the provided xml.
var serializer = new XmlSerializer(typeof(ServiceUsers));
ServiceUsers i;
using (TextReader reader = new StringReader(xml))
{
i = (ServiceUsers)serializer.Deserialize(reader);
}
[XmlRoot(ElementName = "ServiceUsers")]
public class ServiceUsers : List<ServiceUser>
{
}
public class ServiceUser
{
[XmlElement(ElementName = "ID")]
public string Id {get; set;}
}
I think the basis of the problem is your trailing 's' to put it short, You iterate ServiceUser not ServiceUsers
Anyway this runs through fine:
[Fact]
public void CheckIteratorTest()
{
var a = Assembly.GetExecutingAssembly();
string[] resourceNames = a.GetManifestResourceNames();
string nameOf = resourceNames.FirstOrDefault(x => x.Contains("SomeXml"));
Assert.NotNull(nameOf);
using var stream = a.GetManifestResourceStream(nameOf);
Assert.NotNull(stream);
var reader = new StreamReader(stream, Encoding.UTF8);
var serialized = reader.ReadToEnd();
var doc = XDocument.Parse(serialized);
var elemList = doc.Root.Elements("ServiceUser").ToList();
Assert.NotEqual(0, elemList.Count);
foreach(var serviceUser in elemList)
{
System.Diagnostics.Debug.WriteLine($"Name : {serviceUser.Name ?? "n.a."}");
}
}
As being said: XML is case-sensitive. Next issue is .Descendants() returns all the descendant nodes, nested ones, etc, 12 nodes in this case. So NullPointerException will happen even if you fix a "typo".
Here is your fixed code:
XDocument doc = XDocument.Parse(xml);
var xElementList = doc
.Element("ServiceUsers") // picking needed root node from document
.Elements("ServiceUser") // picking exact ServiceUser nodes
.Elements("NAME") // picking actual NAME nodes
.ToList();
foreach (XElement element in xElementList)
{
var TEST = element.Value;
Console.WriteLine(TEST); // do what you were doing instead of console
}
Use doc.Element("ServiceUsers").Elements() to get the<ServiceUser> elements. Then you can loop over the child values of those in a nested loop.
var doc = XDocument.Parse(xml);
foreach (XElement serviceUser in doc.Element("ServiceUsers").Elements()) {
foreach (XElement element in serviceUser.Elements()) {
Console.WriteLine($"{element.Name} = {element.Value}");
}
Console.WriteLine("---");
}
Prints:
ID = 280334
USER_NAME = YVELAMGAMOIYENET12:206322102
UN_ID = 731937
IP = 91.151.136.178
NAME = ?????????????????????: 123456
---
ID = 266070
USER_NAME = ACHIBALANCE:206322102
UN_ID = 731937
IP = 185.139.56.37
NAME = 123456
---
Note: Elements() gets the (immediate) child elements where as Descendants() returns all descendants. Using Elements() gives you a better control and allows you to get the properties grouped by user.
You can also get a specific property like this serviceUser.Element("USER_NAME").Value. Note that the tag names are case sensitive!

Select a child node in XML with specific name using C#

I am trying to find a child element with tag name Reason.
I have XML doc that is basically contains bunch of elements with Entity name.
Reason tag is somewhere inside of Entity(along with other elements).
void IParseResponse.ParseResponseData(XmlDocument responseDocument)
{
List<string> reasons = new List<string>();
var reasonValue = "";
var entityList = responseDocument.GetElementsByTagName("Entity");
if (entityList != null)
{
foreach (XmlNode reason in entityList)
{
reasonValue = //look into current Entity element, find Reason in it and get it's inner text.
reasons.Add(reasonValue);
}
}
}
This is location of Reason element.
<Entity>
<WatchList>
<Match ID="1">
<MatchDetails>
<Reason>
Does anybody have experience with this?
Here's how you can get all the Reason elements.
var xml = "<Entity> <WatchList><Match ID=\"1\"><MatchDetails><Reason>asdasd</Reason></MatchDetails></Match></WatchList></Entity>";
var x = XDocument.Parse(xml);
var reasons = x.Descendants("Reason").ToList();
foreach (var reason in reasons)
{
Console.WriteLine(reason.Value);
}
If you give us a more complete example of your XML I can improve the answer.
Edit:
If you want to use XmlDocument instead you could do this:
XmlNodeList nodes = responseDocument.GetElementsByTagName("Reason");
for (int i = 0; i < nodes.Count; i++)
{
Console.WriteLine(nodes[i].InnerText);
}

how to get value from xml by Linq

i was reading huge xml file of 5GB size by using the following code, and i was success to get the first element Testid but failed to get another element TestMin coming under different namespace
this is the xml i am having
which i am getting as null
.What is wrong here?
EDIT
GMileys answer giving error like The ':' character, hexadecimal value 0x3A, cannot be included in a name
The element es:qRxLevMin is a child element of xn:attributes, but it looks like you are trying to select it as a child of xn:vsDataContainer, it is a grandchild of that element. You could try changing the following:
var dataqrxlevmin = from atts in pin.ElementsAfterSelf(xn + "VsDataContainer")
select new
{
qrxlevmin = (string)atts.Element(es + "qRxLevMin"),
};
To this:
var dataqrxlevmin = from atts in pin.Elements(string.Format("{0}VsDataContainer/{1}attributes", xn, es))
select new
{
qrxlevmin = (string)atts.Element(es + "qRxLevMin"),
};
Note: I changed your string concatenation to use string.Format for readability purposes, either is technically fine to use, but string.Format is a better approach.
What about this approach?
XDocument doc = XDocument.Load(path);
XName utranCellName = XName.Get("UtranCell", "un");
XName qRxLevMinName = XName.Get("qRxLevMin", "es");
var cells = doc.Descendants(utranCellName);
foreach (var cell in cells)
{
string qRxLevMin = cell.Descendants(qRxLevMinName).FirstOrDefault();
// Do something with the value
}
try this code which is very similar to your code but simpler.
using (XmlReader xr = XmlReader.Create(path))
{
xr.MoveToContent();
XNamespace un = xr.LookupNamespace("un");
XNamespace xn = xr.LookupNamespace("xn");
XNamespace es = xr.LookupNamespace("es");
while (!xr.EOF)
{
if(xr.LocalName != "UtranCell")
{
xr.ReadToFollowing("UtranCell", un.NamespaceName);
}
if(!xr.EOF)
{
XElement utranCell = (XElement)XElement.ReadFrom(xr);
}
}
}
actually namespace was the culprit,what i did is first loaded the small section i am getting from.Readform method in to xdocument,then i removed all the namespace,then i took the value .simple :)

A better way to handle XML updation

I have a DataGridView control where some values are popluted.
And also I have an xml file. The user can change the value in the Warning Column of DataGridView.And that needs to be saved in the xml file.
The below program just does the job
XDocument xdoc = XDocument.Load(filePath);
//match the record
foreach (var rule in xdoc.Descendants("Rule"))
{
foreach (var row in dgRulesMaster.Rows.Cast<DataGridViewRow>())
{
if (rule.Attribute("id").Value == row.Cells[0].Value.ToString())
{
rule.Attribute("action").Value = row.Cells[3].Value.ToString();
}
}
}
//save the record
xdoc.Save(filePath);
Matching the grid values with the XML document and for the matched values, updating the needed XML attribute.
Is there a better way to code this?
Thanks
You could do something like this:
var rules = dgRulesMaster.Rows.Cast<DataGridViewRow>()
.Select(x => new {
RuleId = x.Cells[0].Value.ToString(),
IsWarning = x.Cells[3].Value.ToString() });
var tuples = from n in xdoc.Descendants("Rule")
from r in rules
where n.Attribute("id").Value == r.RuleId
select new { Node = n, Rule = r };
foreach(var tuple in tuples)
tuple.Node.Attribute("action").Value = tuple.Rule.IsWarning;
This is basically the same, just a bit more LINQ-y. Whether or not this is "better" is debatable. One thing I removed is the conversion of IsWarning first to string, then to int and finally back to string. It now is converted to string once and left that way.
XPath allows you to target nodes in the xml with alot of power. Microsoft's example of using the XPathNavigator to modify an XML file is as follows:
XmlDocument document = new XmlDocument();
document.Load("contosoBooks.xml");
XPathNavigator navigator = document.CreateNavigator();
XmlNamespaceManager manager = new XmlNamespaceManager(navigator.NameTable);
manager.AddNamespace("bk", "http://www.contoso.com/books");
foreach (XPathNavigator nav in navigator.Select("//bk:price", manager))
{
if (nav.Value == "11.99")
{
nav.SetValue("12.99");
}
}
Console.WriteLine(navigator.OuterXml);
Source: http://msdn.microsoft.com/en-us/library/zx28tfx1(v=vs.80).aspx

How to get XML Elements from XmlDocument object?

Assume that an XmlDocument is successfully loaded with this code:
var doc = new XmlDocument();
doc.Load(stream);
This is a sample portion of the XML stream (the complete XML stream has about 10000 of ProductTable's):
<ProductTable>
<ProductName>Chair</ProductName>
<Price>29.5</Price>
</ProductTable>
Using Linq, how do I access the ProductName and Price elements? Thanks.
I suggest using an XDocument instead of an XmlDocument (the latter is not suited for LINQ to XML). Use the XDocument.Load(...) method to load your "real" XML.
string xml = #"<ProductTable>
<ProductName>Chair</ProductName>
<Price>29.5</Price>
</ProductTable>";
XDocument x = XDocument.Parse(xml);
var tables = x.Descendants("ProductTable");
Dictionary<string,string> products = new Dictionary<string, string>();
foreach (var productTable in tables)
{
string name = productTable.Element("ProductName").Value;
string price = productTable.Element("Price").Value;
products.Add(name, price);
}
If you'd prefer to use sugar-coated SQL like syntax or would like to read up on the topic, this MSDN article is a great place to start.
The following is a more concise version if you feel like using an anonymous type:
XDocument document = XDocument.Parse(xml)
var products = /* products is an IEnumerable<AnonymousType> */
from item in document.Descendants("ProductTable")
select new
{
Name = item.Element("ProductName").Value,
Price = item.Element("Price").Value
};
You could then use this expressive syntax to print the matches in the console:
foreach (var product in products) /* var because product is an anonymous type */
{
Console.WriteLine("{0}: {1}", product.Name, product.Price);
}
Console.ReadLine();

Categories

Resources