Finding Descendents in XML - c#

I have this problem with my C# API that I unfortunately posted incorrectly & got partially incorrect answers, so I'm going to try again since I've still not solved it (trying for hours)
Here's my XML file :
<CHandlingDataMgr>
<HandlingData>
<Item type="CHandlingData">
<handlingName>Plane</handlingName>
<fMass value="140000.000000" />
<SubHandlingData>
<Item type="CFlyingHandlingData">
<handlingType>HANDLING_TYPE_FLYING</handlingType>
<fThrust value="0.630000" />
</SubHandlingData>
</Item>
</Item>
Please note: SubHandlingData is in a separate sub-section within the same item, a 2nd item type is called.
Here's the C# Code :
private void button2_Click(object sender, EventArgs e)
{
var items = doc.Descendants("HandlingData").Elements("Item");
var query = from i in items
select new
{
HandlingName = (string)i.Element("handlingName"), (decimal?)i.Element("fThrust").Attribute("value"),
HandlingType = (string)i.Element("handlingType")
};
StringBuilder test = new StringBuilder();
foreach (var item in query)
{
var k = item.dunno;
test.Append(k);
richTextBox1.Text = test.ToString();
}
}
The above code works fine, but doesn't work with SubHandlingData. This means such values as HandlingType is not seen, I've added the element for this & it returns errors, have also tried including multiple decedents which then doesn't find HandlingName, or HandlingType. I want my output to be if handlingType == "HANDLING_TYPE_FLYING", richtextbox1.text = this.HandlingName. I hope I have explained this clearly enough to gain an answer as this has troubled me for a while.
My Problem in short: Program does not find any SubHandlingData inside my XML document.
Question in short: How to find <SubHandlingData> inside <item> (how to find sub-section of code inside same item)

From #Matthew's edit, you can see there is <Item> not closed within <SubHandlingData>. If your actual XML has such structure then it won't get parsed successfully to XDocument. But if your actual XML has it closed, about like so I assume :
<HandlingData>
<Item type="CHandlingData">
<handlingName>Plane</handlingName>
<fMass value="140000.000000" />
<SubHandlingData>
<Item type="CFlyingHandlingData">
<handlingType>HANDLING_TYPE_FLYING</handlingType>
<fThrust value="0.630000" />
</Item>
</SubHandlingData>
</Item>
</HandlingData>
... then we can continue. You can try to follow path from outer Item to handlingType which is : SubHandlingData > Item > handlingType, to get handlingType data from current outer item :
var query = from i in items
select new
{
HandlingName = (string)i.Element("handlingName"),
HandlingType = (string)i.Element("SubHandlingData")
.Element("Item")
.Element("handlingType")
};

Related

c# Linq XML - Why Is Whitespace Being Added to Elements With Quotes / Namespace?

A portion of my c# .NET program contains code to modify elements within an XML document. The code works fine in terms of modifying the values based on the variables I'm setting elsewhere in the code, but the problem is that whitespace is being added to all of the the elements when the xml file is saved with the updates.
I am not accessing this element at all in my code. I am assuming that it's because of the quotation marks for the algorithm namespace value, because I can't see any other reason why this would happen. I am using Preserve Namespace on load, and Disable Formatting on save.
So question is, why is it adding this extra whitespace, and how can I stop it?
XML (Source File)
<?xml version="1.0" encoding="UTF-8"?>
<PackingList xmlns="http://www.smpte-ra.org/schemas/2067-2/2016/PKL">
<Id>urn:uuid:296a656c-3610-4de1-9b08-2aa63245788d</Id>
<AnnotationText>JOT_Sample</AnnotationText>
<IssueDate>2018-02-16T20:59:42-00:00</IssueDate>
<Issuer>Generic</Issuer>
<Creator>Generic</Creator>
<AssetList>
<Asset>
<Id>urn:uuid:744f36b7-fc7e-4179-8b75-c71c18f98156</Id>
<AnnotationText>Video_744f36b7-fc7e-4179-8b75-c71c18f98156.mxf</AnnotationText>
<Hash>8HhnKnLn+Lp/Ik9i94Ml4SXAxH4=</Hash>
<Size>14568486</Size>
<Type>application/mxf</Type>
<OriginalFileName>Video_744f36b7-fc7e-4179-8b75-c71c18f98156.mxf</OriginalFileName>
<HashAlgorithm Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
</Asset>
<Asset>
<Id>urn:uuid:bf5438ea-ba58-4ae0-a64a-5d23cee2ebb3</Id>
<AnnotationText>Audio_bf5438ea-ba58-4ae0-a64a-5d23cee2ebb3.mxf</AnnotationText>
<Hash>Wg4aEAE5Ji9e14ZyGkvfUUjBwCw=</Hash>
<Size>4341294</Size>
<Type>application/mxf</Type>
<OriginalFileName>Audio_bf5438ea-ba58-4ae0-a64a-5d23cee2ebb3.mxf</OriginalFileName>
<HashAlgorithm Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
</Asset>
</AssetList>
</PackingList>
XML (Output File)
<?xml version="1.0" encoding="UTF-8"?>
<PackingList xmlns="http://www.smpte-ra.org/schemas/2067-2/2016/PKL">
<Id>urn:uuid:296a656c-3610-4de1-9b08-2aa63245788d</Id>
<AnnotationText>JOT_Sample</AnnotationText>
<IssueDate>2018-02-16T20:59:42-00:00</IssueDate>
<Issuer>Generic</Issuer>
<Creator>Generic</Creator>
<AssetList>
<Asset>
<Id>urn:uuid:744f36b7-fc7e-4179-8b75-c71c18f98156</Id>
<AnnotationText>Video_744f36b7-fc7e-4179-8b75-c71c18f98156.mxf</AnnotationText>
<Hash>8HhnKnLn+Lp/Ik9i94Ml4SXAxH4=</Hash>
<Size>14568486</Size>
<Type>application/mxf</Type>
<OriginalFileName>Video_744f36b7-fc7e-4179-8b75-c71c18f98156.mxf</OriginalFileName>
<HashAlgorithm Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
</Asset>
<Asset>
<Id>urn:uuid:bf5438ea-ba58-4ae0-a64a-5d23cee2ebb3</Id>
<AnnotationText>Audio_bf5438ea-ba58-4ae0-a64a-5d23cee2ebb3.mxf</AnnotationText>
<Hash>Wg4aEAE5Ji9e14ZyGkvfUUjBwCw=</Hash>
<Size>4341294</Size>
<Type>application/mxf</Type>
<OriginalFileName>Audio_bf5438ea-ba58-4ae0-a64a-5d23cee2ebb3.mxf</OriginalFileName>
<HashAlgorithm Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
</Asset>
</AssetList>
</PackingList>
Code (partial):
XDocument pkldoc = XDocument.Load(packing, LoadOptions.PreserveWhitespace);
var pklns = pkldoc.Root.GetDefaultNamespace();
var pkluuid = pkldoc.Descendants(pklns + "Id").FirstOrDefault().Value;
var pklassetElements = pkldoc.Descendants(pklns + "Asset");
foreach (var pklasset in pklassetElements)
{
var idElement = pklasset.Descendants(pklns + "Id").First();
if (!idElement.Value.Equals(cpluuid))
continue;
SetNewValue(pklasset, pklns + "OriginalFileName", outfile);
}
void SetNewValue(XElement currentElement, XName elementName, string newValue)
{
var matchingElements = currentElement.Descendants(elementName);
if (matchingElements.Any())
{
foreach (var element in matchingElements)
element.SetValue(newValue);
}
}
pkldoc.Save(packing, SaveOptions.DisableFormatting);
FileInfo fi = new FileInfo(packing);
var pklsize = fi.Length;
This works, though not very clean on my part.
string text = File.ReadAllText(packing);
text = text.Replace(" />", "/>");
File.WriteAllText(packing, text);
UPDATE
This is the solution. Thanks you #asherber !
var textToSave = pkldoc.ToString(SaveOptions.DisableFormatting).Replace(" />", "/>");
File.WriteAllText(packing, textToSave);

GetElementByID.GetElementsByTagName returns null

My friend wrote this piece of XML code for simple testing in our game when it comes to loading and writing save data. The problem is that his code does not work at all and I have never wrote any piece of XML code before so this is new for me and I decided to learn XML.
All it wants is the x and y values to create a new Tile object.
When running the code it gives the error:
System.NullReferenceException was unhandled
HResult=-2147467261
Message=Object reference not set to an instance of an object.
TL;DR It loads simple Tiles and all it's looking for is the x and y position to later add to a list that is accessed in the Level class.
The code he wrote:
public class XmlHandler
{
private List<Base.Tile> tiles;
public XmlHandler()
{
}
public void Load()
{
XmlDocument documentFile = new XmlDocument();
documentFile.Load(#"C:\Tiles\0.xml");
var listOfTiles = documentFile.GetElementById("tiles").GetElementsByTagName("tile");
foreach(XmlElement tile in listOfTiles)
{
var x = ((XmlElement)tile.GetElementsByTagName("position")[0]).GetAttribute("x");
var y = ((XmlElement)tile.GetElementsByTagName("position")[0]).GetAttribute("y");
Classes.Base.Tile t = new Base.Tile(new Vector2(float.Parse(x), float.Parse(y)));
this.tiles.Add(t);
}
}
public List<Base.Tile> GetTiles()
{
return this.tiles;
}
}
The current XML file, modified from the original as shown below
<tiles>
<tile>
<position x="10" y="20" />
</tile>
<tile>
<position x="50" y="20" />
</tile>
<tile>
<position x="30" y="40" />
</tile>
</tiles>
And this is the original XML that I modified because the first line caused errors
<?xml encoding="utf-8"?>
<tiles>
<tile>
<id>1</id>
<position x="10" y="20" />
</tile>
<tile>
<id>2</id>
<position x="50" y="20" />
</tile>
<tile>
<id>3</id>
<position x="30" y="40" />
</tile>
</tiles>
Thanks for viewing/reading. Any help is appreciated!
The bug is here:
var listOfTiles = documentFile.GetElementById("tiles").GetElementsByTagName("tile");
Change it this way:
var listOfTiles = documentFile.GetElementsByTagName("tiles").GetElementsByTagName("tile");
<tiles> is a tag and it hasn't got any id.
I'm not sure whether this is the complete class or not, but firstly it looks like you haven't created a list for the tiles.
Somewhere before you start adding tiles to the list 'tiles', you need to write:
tiles = new List();
I suggest the constructor.
It would also be helpful to know where the null reference exception is happening. Make sure your list is set, and then if the problem still occurs, add a comment and I'll run your code on my machine.
Per the docs, GetElementById will return elements with an id attribute as defined in a DTD (or just id by default). You don't have any id attributes, so this returns null - hence the exception.
If you change the offending line to this:
var listOfTiles = documentFile.GetElementsByTagName("tile");
Then your current code will work fine. However... LINQ to XML is a far cleaner API, you could write your entire method as below:
var doc = XDocument.Load(#"C:\Tiles\0.xml");
var tiles =
from tile in doc.Descendants("tile")
from position in tile.Elements("position")
let x = (float)position.Attribute("x")
let y = (float)position.Attribute("y")
select new Base.Tile(new Vector2(x, y));
this.tiles = tiles.ToList();

reading an xml file in C# using CsQuery

using CsQuery;
namespace CSQuery
{
class Program
{
static void Main(string[] args)
{
var dom = CQ.Create(/*I am not sure what goes here*/);
//Not sure if this is the correct setup as well
CQ mf = dom["MANUFACTURER"];
CQ md = dom["MODEL"];
Console.WriteLine(mf);
Console.WriteLine(md);
Console.ReadKey();
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
--------------------------------------------------------
PARTS:
Title: Computer Parts
<ITEM>Motherboard</ITEM>
<MANUFACTURER>ASUS</MANUFACTURER>
<MODEL>P3B-F</MODEL>
<COST> 123.00</COST>
<ITEM>Video Card</ITEM>
<MANUFACTURER>ATI</MANUFACTURER>
<MODEL>All-in-Wonder Pro</MODEL>
<COST>160.00</COST>
<ITEM> Monitor </ITEM>
<MANUFACTURER>LG Electronics</MANUFACTURER>
<MODEL> 995E</MODEL>
<COST> 290.00</COST>
</PART></PARTS>
Above is my code I have written so far I am trying to extract the MANUFACTURER and MODEL from the sample given xml code. When I compile I get an error message saying source can not be found and I think it may be a problem with my setup and I am unclear on what exactly is suppose to go into my CQ.Create() as a parameter(I tried putting in the exact parts.xml file but that didn't help).

XML to ListView

I have made a script in C# that should load data from a XML file into a ListView.
This is the XML file I used to test :
<?xml version="1.0" encoding="utf-8"?>
<Items>
<wordExample languageOne="Пока" languageTwo="Doei" languageThree="Goodbye" />
<wordExample languageOne="1" languageTwo="2" languageThree="3" />
<wordExample languageOne="4" languageTwo="5" languageThree="6" />
<wordExample languageOne="7" languageTwo="8" languageThree="9" />
</Items>
Now I get an error when I try to load the XMl into the ListView and I really don't know what it could be, this is actually the first time I try to use XML in C#.
This is the code used to load the XML into the ListView :
public void ImportXMLToListView(ListView listview)
{
DialogResult dr = OPEN_FILE_DIA.ShowDialog();
if (dr == DialogResult.OK)
{
XDocument doc = XDocument.Load(OPEN_FILE_DIA.FileName);
int counter = 0;
foreach (var dm in doc.Descendants("Items"))
{
string tmpOne = dm.Attribute("languageOne").Value;
string tmpTwo = dm.Attribute("languageTwo").Value;
string tmpThree = dm.Attribute("languageThree").Value;
counter++;
ListViewItem lvi;
lvi = new ListViewItem(tmpOne);
lvi.SubItems.Add(tmpTwo);
lvi.SubItems.Add(tmpThree);
listview.Items.Add(lvi);
}
}
}
Am I doing something wrong??
This is the error I get : (Object reference not set to an instance of an object.)
Please tell me what I do wrong I really try to understand :S
language attributes belongs to your wordExample items. You need doc.Descendants("wordExample")
foreach (var dm in doc.Descendants("wordExample"))
{
string tmpOne = (string)dm.Attribute("languageOne");
string tmpTwo = (string)dm.Attribute("languageTwo");
string tmpThree = (string)dm.Attribute("languageThree");
...
}
And you can use explicit cast instead of directly accessing Value property to avoid NullReferenceException.

XMLResponse element show in list

I'm doing a HttpWebrequest by using c#. I get the following response
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Siri version="1.0" xmlns="http://www.siri.org.uk/">
<ServiceDelivery>
<ResponseTimestamp>2013-03-21T11:40:13.514Z</ResponseTimestamp>
<StopMonitoringDelivery version="1.0">
<ResponseTimestamp>2013-03-21T11:40:13.514Z</ResponseTimestamp>
<RequestMessageRef>12345</RequestMessageRef>
<MonitoredStopVisit>
<RecordedAtTime>2013-03-21T11:40:13.514Z</RecordedAtTime>
<MonitoringRef>020035811</MonitoringRef>
<MonitoredVehicleJourney>
<FramedVehicleJourneyRef>
<DataFrameRef>-</DataFrameRef>
<DatedVehicleJourneyRef>-</DatedVehicleJourneyRef>
</FramedVehicleJourneyRef>
<VehicleMode>bus</VehicleMode>
<PublishedLineName>1</PublishedLineName>
<DirectionName>Kempston</DirectionName>
<OperatorRef>STB</OperatorRef>
<MonitoredCall>
<AimedDepartureTime>2013-03-21T11:41:00.000Z</AimedDepartureTime>
<ExpectedDepartureTime>2013-03-21T11:44:27.000Z</ExpectedDepartureTime>
</MonitoredCall>
</MonitoredVehicleJourney>
</MonitoredStopVisit>
</StopMonitoringDelivery>
</ServiceDelivery>
</Siri>
This response is saved in a string variable called "ResponseFromServer"
Now I just want to show the 'ExpectedDepartureTime' in a listbox
I tried to do this with the following code:
//XMLResponse put in documentRoot
XDocument documentRoot = XDocument.Parse(responseFromServer);
//Linq To XML
var documents =
(from docs in documentRoot.Descendants("ServiceDelivery").Descendants("StopMonitoringDelivery").Descendants("MonitoredStopVisit").Descendants("MonitoredVehicleJourney").Descendants("MonitoredCall")
select new
{
dep = docs.Element("ExpectedDepartureTime").Value
});
//Show every ExpectedDepartureTime
foreach (var i in documents)
{
lstHours.Items.Add(i);
MessageBox.Show(i.ToString());
}
When I try this nothing happens (the messagebox is not appearing and in the listbox i see nothnig). I also try to Descendant first the tag without success...
Can anybody help me with this issue?
Thanks!
You need to specify namespace like this and then use one method Descendants
XNamespace ns = "http://www.siri.org.uk/";
var documents =
documentRoot.Descendants(ns + "MonitoredCall")
.Select(x => x.Element(ns + "ExpectedDepartureTime").Value);
now you can
foreach (var i in documents)
{
lstHours.Items.Add(i);
MessageBox.Show(i.ToString());
}
prints
2013-03-21T11:44:27.000Z

Categories