Unable to read XML correctly - c#

I found an article to help with XML parsing:
http://geekswithblogs.net/pabothu/archive/2014/04/29/reading-a-complex-xml-using-linq-in-c-sharp.aspx.
I am trying to read the XML but I am getting a null object. I am a bit confused what I am doing wrong since I am not able to debug into those LINQ queries.
var containers =
from container in xmlDoc.Descendants("container")
//where container.Attribute("ID").Value != "0"
select new Container
{
id = Convert.ToInt32(container.Element("id").Value),
name = container.Element("name").Value,
enabled = Convert.ToBoolean(container.Element("enabled").Value),
components = new List<Component>(
from component in container.Descendants("component")
select new Component
{
id = Convert.ToInt32(component.Element("id").Value),
name = component.Element("name").Value,
type = component.Element("type").Value,
connectors = new List<Connector>(
from connector in component.Descendants("connector")
select new Connector
{
id = Convert.ToInt32(component.Element("id").Value),
name = connector.Element("name").Value,
source = connector.Element("id").Value,
destination = component.Element("id").Value
})
})
};
And here is the XML:
<?xml version="1.0" encoding="UTF-8"?>
<simplevisio>
<container>
<id>1</id>
<name>Naming</name>
<component>
<id>2</id>
<type>Server</type>
<name>First</name>
<connector>
<id>3</id>
<name>.</name>
</connector>
<connector>
<id>5</id>
<name>isShortName()</name>
</connector>
</component>
<component>
<id>3</id>
<type>Server</type>
<name>Last</name>
<connector>
<id>5</id>
<name>isShortName()</name>
</connector>
</component>
<enable>true</enable>
<connector>
<id>5</id>
<name>getFullname()</name>
</connector>
</container>
<container>
<id>4</id>
<name></name>
<component>
<id>5</id>
<type>Server</type>
<name>FirstLast</name>
</component>
<enable>false</enable>
</container>
</simplevisio>

You're querying for enabled elements, but your sample XML contains enable elements. That's why you're getting NullReferenceException.
Change
enabled = Convert.ToBoolean(container.Element("enabled").Value),
to
enabled = Convert.ToBoolean(container.Element("enable").Value),
or update your XML schema to match your query.

Related

Load XML containing multiple lists to multiple DataTables

I have an XML that has the below structure:
<?xml version="1.0" encoding="utf-8"?>
<n0:Response xmlns:n0="urn:sap-com:document:sap:rfc:functions">
<Cars>
<item>
<ID>1</ID>
<TYPE>SUV</TYPE>
<YEAR>2022</YEAR>
</item>
<item>
<ID>2</ID>
<TYPE>Convertible</TYPE>
<YEAR>2021</YEAR>
</item>
</Cars>
<Employees>
<item>
<ID>1</ID>
<NAME>John</NAME>
<STATUS>1</STATUS>
<PHONE>000000000</PHONE>
</item>
<item>
<ID>2</ID>
<NAME>Sam</NAME>
<STATUS>2</STATUS>
<PHONE>000000000</PHONE>
</item>
<item>
<ID>3</ID>
<NAME>Jane</NAME>
<STATUS>1</STATUS>
<PHONE>000000000</PHONE>
</item>
</Employees>
</n0:Response>
(this is just a sample, the final file will have more than 10k items per row)
I need to load that file to two DataTables, each having the correct values.
I do this by creating DataSet, loading XML, and filtering the data table.
My DataSet has 3 tables:
but when I try to access the correct data table I get all the items instead of the correct ones (I get items from the entire XML):
var rel = ds.Relations.OfType<DataRelation>()
.FirstOrDefault(x => x.ParentTable.TableName == "Cars")?.ChildTable;
this is the result:
I managed to filter the data by adding a Select statement like below:
var ds = new DataSet();
using Stream stream = new FileStream("Sample.xml", FileMode.Open, FileAccess.Read);
ds.ReadXml(stream);
var table1 = ds.Relations.OfType<DataRelation>()
.FirstOrDefault(x => x.ParentTable.TableName == "Cars")?
.ChildTable.Select("Cars_Id = 0").CopyToDataTable();
var table2 = ds.Relations.OfType<DataRelation>()
.FirstOrDefault(x => x.ParentTable.TableName == "Employees")?
.ChildTable.Select("Employees_Id = 0").CopyToDataTable();
but this isn't generic and I'd like to be able to access the correct DataTable only by name (the node name from XML).
My question is similar to How to get multiple tables in Dataset from XML, but the provided answer didn't solve the issue.

Unable to parse xml string using Xdocument and Linq

I would like to parse the below xml using XDocument in Linq.
<?xml version="1.0" encoding="UTF-8"?>
<string xmlns="http://tempuri.org/">
<Sources>
<Item>
<Id>1</Id>
<Name>John</Name>
</Item>
<Item>
<Id>2</Id>
<Name>Max</Name>
</Item>
<Item>
<Id>3</Id>
<Name>Ricky</Name>
</Item>
</Sources>
</string>
My parsing code is :
var xDoc = XDocument.Parse(xmlString);
var xElements = xDoc.Element("Sources")?.Elements("Item");
if (xElements != null)
foreach (var source in xElements)
{
Console.Write(source);
}
xElements is always null. I tried using namespace as well, it did not work. How can I resolve this issue?
Try below code:
string stringXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><string xmlns=\"http://tempuri.org/\"><Sources><Item><Id>1</Id><Name>John</Name></Item><Item><Id>2</Id><Name>Max</Name></Item><Item><Id>3</Id><Name>Ricky</Name></Item></Sources></string>";
XDocument xDoc = XDocument.Parse(stringXml);
var items = xDoc.Descendants("{http://tempuri.org/}Sources")?.Descendants("{http://tempuri.org/}Item").ToList();
I tested it and it correctly shows that items has 3 lements :) Maybe you used namespaces differently (it's enough to inspect xDoc objct in object browser and see its namespace).
You need to concatenate the namespace and can directly use Descendants method to fetch all Item nodes like:
XNamespace ns ="http://tempuri.org/";
var xDoc = XDocument.Parse(xmlString);
var xElements = xDoc.Descendants(ns + "Item");
foreach (var source in xElements)
{
Console.Write(source);
}
This prints on Console:
<Item xmlns="http://tempuri.org/">
<Id>1</Id>
<Name>John</Name>
</Item><Item xmlns="http://tempuri.org/">
<Id>2</Id>
<Name>Max</Name>
</Item><Item xmlns="http://tempuri.org/">
<Id>3</Id>
<Name>Ricky</Name>
</Item>
See the working DEMO Fiddle

XML DataGrid Where Certain Nodes Are Empty

I am attempting to bind an XML file to a DataGrid. I am only bind the the "Transactions". What I cannot figure out is how to bind only data that has empty nodes. For example, the transaction that has "UserName" of "NSmith" does not have a value for "CustomerFirst".
I want only this child to be bound to the DataGrid
<Root>
<Header>
<value1>0000000</value1>
<value2>1</value2>
<value3>100.00</value3>
</Header>
<Transactions>
<Txn>
<id></id>
<UserName>BSmith</User>
<CustomerFirst>Bob</CustomerFirst>
...
</Txn>
<Txn>
<id></id>
<UserName>NSmith</User>
<CustomerFirst></CustomerFirst>
...
</Txn>
</Transactions>
</Root>
Here is my C# code:
serverPath = Server.MapPath("App_Data/" + xmlFileName);
DataSet dsBillPay = new DataSet();
dsBillPay.ReadXml(serverPath);
dgBillPay.DataSource = dsBillPay.Tables[1];
dgBillPay.DataBind();
The .Tables[1] is selecting the "Transactions".
Now the question is selecting data that has empty nodes.
Thank you in advance.
You can use Linq-to-Xml to filter out elements that have all of their child-elements specified with values and include only those with missing data.
The following example retrieves users that have an empty element but allows AddressTwo to be empty.
string xmlText = #"<Root>
<Header>
<value1>0000000</value1>
<value2>1</value2>
<value3>100.00</value3>
</Header>
<Transactions>
<Txn>
<id>1</id>
<UserName>BSmith</UserName>
<CustomerFirst>Bob</CustomerFirst>
</Txn>
<Txn>
<id>2</id>
<UserName>NSmith</UserName>
<CustomerFirst></CustomerFirst>
</Txn>
<Txn>
<id></id>
<UserName>JSmith</UserName>
<CustomerFirst>James</CustomerFirst>
</Txn>
<Txn>
<id>4</id>
<UserName>KSmith</UserName>
<CustomerFirst>Kevin</CustomerFirst>
<AddressTwo></AddressTwo>
</Txn>
</Transactions>
</Root>";
var root = XElement.Parse(xmlText);
var elementsThatCanBeEmpty = new HashSet<XName>
{
XName.Get("AddressTwo")
};
var transactionsWithoutCustomerFirst =
from transactions in root.Elements(XName.Get("Transactions")).Elements()
where transactions.Elements().Any
(
el =>
String.IsNullOrEmpty(el.Value) &&
!elementsThatCanBeEmpty.Contains(el.Name)
)
select transactions;
foreach(var t in transactionsWithoutCustomerFirst)
{
Console.WriteLine(t.Element(XName.Get("UserName")).Value);
}

How to use LINQ to XML to retrieve nested arrays?

Here's a sample of the XML I want to read:
<?xml version="1.0" encoding="UTF-8"?>
<hash>
<result>
<properties type="array">
<property>
<registers type="array">
<register>
<dials type="integer">6</dials>
</register>
<register>
<dials type="integer">6</dials>
</register>
</registers>
<unit-balance type="integer">-104</unit-balance>
</property>
</properties>
<account-number>9001234</account-number>
</result>
<version>1.0</version>
</hash>
I can read the first level with the following code, but how to get the registers, and have them associated with the corresponding property?
var rawProperties = from property in customerXml.Descendants("property")
select new
{
UnitBalance = property.Element("unit-balance").Value
};
Something like this:
var rawProperties = customerXml.Descendants("property")
.Select(arg =>
new
{
UnitBalance = arg.Element("unit-balance").Value,
Registers = arg.Descendants("dials").Select(x => x.Value).ToList()
})
.ToList();

linq to xml navigate through xml c#

I have some XML and need to be able to read the data within.
A sample of the XML is
<?xml version="1.0" ?>
<ConsumeLeadRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<LeadType>Mortgage</LeadType>
<LeadXml>
<ns1:LeadAssigned xmlns:ns1="http://YaddaYadda" xmlns:ns0="http://YaddaYadda" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns0:Lead>
<Reference>1234</Reference>
<Product>
<Mnemonic>Mortgage</Mnemonic>
<Description>Mortgage Leads</Description>
<SubType>Other</SubType>
</Product>
<ExtendedInfo>
<Mortgage>
<MortgageValue>75000</MortgageValue>
<MortgageValueLowerBound>1</MortgageValueLowerBound>
<MortgageValueUpperBound>500</MortgageValueUpperBound>
<PropertyValue>100000</PropertyValue>
<PropertyValueLowerBound>1</PropertyValueLowerBound>
<PropertyValueUpperBound>500</PropertyValueUpperBound>
<Adverse>false</Adverse>
<FirstTime>false</FirstTime>
</Mortgage>
</ExtendedInfo>
<Applicants>
<Applicant1>
<Title>Mr</Title>
<Forename>SampleForename</Forename>
<Surname>SampleSurname</Surname>
<DateOfBirth>1903-02-01</DateOfBirth>
<Smoker>false</Smoker>
<TelephoneNumbers>
<TelephoneNumber>
<Number>01244123456</Number>
<Type>Mobile</Type>
</TelephoneNumber>
</TelephoneNumbers>
<EmailAddresses>
<EmailAddress>
<Email>test#moneysupermarket.com</Email>
<Type>Business</Type>
</EmailAddress>
</EmailAddresses>
<Addresses>
<Address>
<Street>Sample Street</Street>
<District>Sample District</District>
<Town>Sample Town</Town>
<County>Sample County</County>
<Postcode>CH53UZ</Postcode>
<Type>Home</Type>
</Address>
</Addresses>
</Applicant1>
</Applicants>
</ns0:Lead>
<Assignment>
<Price>20</Price>
<AssignmentDateTime>2010-02-01T00:00:00</AssignmentDateTime>
<Subscription>
<Reference>1234</Reference>
<Subscriber>
<Title>Mr</Title>
<Forename>SampleForename</Forename>
<Surname>SampleSurname</Surname>
</Subscriber>
</Subscription>
<Account>
<Reference>1234</Reference>
<CompanyName>Sample Company</CompanyName>
</Account>
<LeadType>SampleLeadType</LeadType>
<TerritoryName>UNITED KINGDOM</TerritoryName>
</Assignment>
</ns1:LeadAssigned>
</LeadXml>
<AuthenticationUsername>Username</AuthenticationUsername>
<AuthenticationPassword>Password</AuthenticationPassword>
</ConsumeLeadRequest>
Using Linq to XML how do i navigate to the items?
Thanks
Sp
I have tried a few things like
XDocument Leads = XDocument.Load(#"C:\Users\Steven.Pentleton\AppData\Local\Temporary Projects\PAALeadImport\PAAExmple.xml");
var Lead = (from L in Leads.Descendants("Lead")
select new { LeadType = (string)L.Element("Reference") }).ToList();
var S = Lead.First();
string T = S.LeadType;
Are you looking for XDcoument or XElement in linq
Namespace: using System.Xml.Linq;
I guess you are looking for a Linq To Xml guide

Categories

Resources