I've got an XML file that I want to turn in to a list of POCO objects.
I have the following working code to read the XML and create objects from it. I just want to check this is a good way to do this and I'm not missing any tricks. In particular with regards to the nested Linq query.
XDocument xmlDoc = XDocument.Load(path);
var q = from file in xmlDoc.Descendants("File")
select new ImportDefinition()
{
Name = file.Attribute("Name").Value,
TypeName = file.Attribute("TypeName").Value,
ColumnMappings =
(
from map in file.Descendants("ColumnMap")
select new ColumnMap()
{
DatabaseColumn = new Column()
{
Name = map.Element("DatabaseColumn").Attribute("Name").Value
}
}
).ToList<ColumnMap>()
};
List<ImportDefinition> def = q.ToList<ImportDefinition>();
Thanks
Maybe try an explicit conversion
public class ColumnMap
{
public static explicit operator ColumnMap(XElement xElem)
{
return new ColumnMap()
{
DatabaseColumn = new Column()
{
Name = xElem.Element("DatabaseColumn").Attribute("Name").Value
}
};
}
}
public class ImportDefinition
{
public static explicit operator ImportDefinition(XElement xElem)
{
return new ImportDefinition()
{
Name = (string)xElem.Attribute("Name"),
TypeName = (string)xElem.Attribute("TypeName"),
Size = (int)xElem.Attribute("Size"),
LastModified = (DateTime?)xElem.Attribute("LastModified"),
ColumnMappings = xElem.Descendants("ColumnMap").Select(xelem => (ColumnMap)xelem).ToList()
};
}
}
Then use it like so:
XDocument xmlDoc = XDocument.Load(path);
List<ImportDefinition> importDefinitions = xmlDoc.Descendants("File").Select(xElem => (ImportDefinition)xElem).ToList()
In case your POCO objects do not only have string properties, XElement and XAttribute provide a wide selection of conversion operators to other types, including nullables in case the element/attribute doesn't exist.
Example:
XDocument xmlDoc = XDocument.Load(path);
var q = from file in xmlDoc.Descendants("File")
select new ImportDefinition()
{
Name = (string)file.Attribute("Name"),
TypeName = (string)file.Attribute("TypeName"),
Size = (int)file.Attribute("Size"),
LastModified = (DateTime?)file.Attribute("LastModified"),
// ...
};
Related
I am trying to convert Netsuite Record(CashSale) into XML equivalent using XMLSerializer in c# application. However properties with datatype double not reflected in XML string
I have created a class in c# with double datatype property , I can see the property and value in xml string
I have tried converting Netsuite Cashsale class to xml string. Double datatype properties are not reflected in the xml string
CashSale cs = new CashSale();
cs.altHandlingCost = Convert.ToDouble(10.73.ToString(), CultureInfo.CurrentCulture);
cs.entity = new RecordRef { internalId = "311", type = RecordType.customer };
cs.externalId = "54658";
cs.memo = "POS Memo";
cs.tranDate = DateTime.Now.AddDays(-1);
cs.undepFunds = false;
cs.account = new RecordRef { internalId = "915" };
cs.subsidiary = new RecordRef { internalId = "2" };
cs.location = new RecordRef { internalId = "101" };
CashSaleItem[] item = { new CashSaleItem { amount = 10,taxAmount=1, taxCode = new RecordRef { internalId = "7" }, description = "dec", item = new RecordRef { externalId = "4000Bev" } } };
cs.itemList = new CashSaleItemList { item = item };
var a=Serialize(cs);
WriteResponse writeRes = Client.Service.upsert(cs);
public static string Serialize(object dataToSerialize)
{
if (dataToSerialize == null) return null;
using (StringWriter stringwriter = new System.IO.StringWriter())
{
var serializer = new XmlSerializer(dataToSerialize.GetType());
serializer.Serialize(stringwriter, dataToSerialize);
return stringwriter.ToString();
}
}
Expected: For Netsuite class, all properties including double datatype should be converted into XML string
Actual: Properties with datatype Double are not converted into XML
Minimum Reprocable Steps:
Create a Web Reference using https://webservices.netsuite.com/wsdl/v2019_1_0/netsuite.wsdl
Create a object for CashSale
Assign some values for double datatype fields alongwith others.
Serialise to XML string
This may help you out:
public string ToXML()
{
using(var stringwriter = new System.IO.StringWriter())
{
var serializer = new XmlSerializer(this.GetType());
serializer.Serialize(stringwriter, this);
return stringwriter.ToString();
}
}
public static YourClass LoadFromXMLString(string xmlText)
{
using(var stringReader = new System.IO.StringReader(xmlText))
{
var serializer = new XmlSerializer(typeof(YourClass ));
return serializer.Deserialize(stringReader) as YourClass ;
}
}
I have found solution for this issue:
Changes Done: I have added one more boolean field amountspecified in request and set it to true
Basically here's my code which I'm having trouble with. Insanely new to mongoDB and would love to understand how to get values out of a JSON string that is returns in the variable 'line'.
public string get_data()
{
var client = new MongoClient();
var db = client.GetDatabase("test");
var collection = db.GetCollection<BsonDocument>("metacorp");
var cursor = collection.Find("{'movie_name' : 'Hemin'}").ToCursor();
var line = "";
foreach (var document in cursor.ToEnumerable())
{
using (var stringWriter = new StringWriter())
using (var jsonWriter = new JsonWriter(stringWriter))
{
var context = BsonSerializationContext.CreateRoot(jsonWriter);
collection.DocumentSerializer.Serialize(context, document);
line = stringWriter.ToString();
}
}
var js = new JavaScriptSerializer();
var d = js.Deserialize<dynamic>(line);
var a = d["movie_name"];
return line;
}
This is the output I get if I return line:
{ "_id" : ObjectId("58746dcafead398e4d7233f5"), "movie_name" : "Hemin"
}
I want to be able to fetch the value 'Hemin' into 'a'.
I know this is not what you're asking for but since you're using the c# driver then I would recommend the following. Assumes you have a c# class corresponding to metacorp collection or at least a serializer that handles it. Hope it helps.
var client = new MongoClient();
var db = client.GetDatabase("test");
var collection = db.GetCollection<MetaCorp>("metacorp");
var m = collection.SingleOrDefault(x => x.Movie_Name == "Hemin"); // Assuming 0 or 1 with that name. Use Where otherwise
var movieName = "Not found";
if(m!= null)
movieName = m.Movie_Name;
You could have your dto class for movie ans just fetch the data from collection:
public class Movie
{
public ObjectId Id { get; set; }
public string movie_name { get; set;}
}
...
var client = new MongoClient();
var db = client.GetDatabase("test");
var collection = db.GetCollection<BsonDocument>("metacorp");
var movies = collection.Find(x=>x.movie_name == "Hemin").ToEnumerable();
I am building an MVC App in C# and am currently working on a method to load an xml document into a file stream and iterate through the nodes and save the data into my model objects.
It is all working fine but I am hard coding the relationship between the object property and the xml attribute name. I was wondering if there is a smart way to associated the two so I can run it all through a for each loop.
This is the code I have currently and it works, but I would like to make it more generic
OLD CODE
var xmlDoc = LoadXmlFileIntoStream("WSAPayCode.xml");
var elementCollection = ExtractDescendants(xmlDoc, "WSAPayCode");
foreach (var element in elementCollection)
{
var abbreviationChar = element.Attribute("AbbreviationChar");
var payCode = new PayCode
{
Name = element.Attribute("Name").Value,
AutoResolved = element.Attribute("AutoResolved").Value.IsBool(),
EditExcuseAbsn = element.Attribute("EditExcuseAbsn").Value.IsBool(),
PersistPceSw = element.Attribute("PersistPceSw").Value.IsBool(),
AbbreviationChar = (string)element.Attribute("AbbreviationChar"),
EditCntToCdotSw = element.Attribute("EditCntToCdotSw").Value.IsBool(),
EditAffShfTotal = element.Attribute("EditAffShfTotal").Value.IsBool(),
EditCntToOt = element.Attribute("EditCntToOt").Value.IsBool(),
PayUsingWeightedAverageRate = element.Attribute("PayUsingWeightedAverageRate").Value.IsBool(),
RequiresMgrApproval = element.Attribute("RequiresMgrApproval").Value.IsBool(),
WeightedAverageRateIsComputedDaily =
element.Attribute("WeightedAverageRateIsComputedDaily").Value.IsBool(),
JustAutoResExpAsWorked = element.Attribute("JustAutoResExpAsWorked").Value.IsBool(),
AssociatedDurationPayCodeName = element.Attribute("AssociatedDurationPayCodeName").Value,
WeightedAverageRateContributionsUseAnAdjustedRate =
element.Attribute("WeightedAverageRateContributionsUseAnAdjustedRate").Value.IsBool(),
ScheduleHoursType = element.Attribute("ScheduleHoursType").Value,
CheckAvlbltySw = element.Attribute("CheckAvlbltySw").Value.IsBool(),
WageAddition = (string)element.Attribute("WageAddition"),
VisibleInMainArea = element.Attribute("VisibleInMainArea").Value.IsBool(),
IsMoneyCategory = element.Attribute("IsMoneyCategory").Value.IsBool(),
AmountType = element.Attribute("AmountType").Value,
VisibleInReport = element.Attribute("VisibleInReport").Value.IsBool(),
ContributesToWeightedAverageRates =
element.Attribute("ContributesToWeightedAverageRates").Value.IsBool(),
UnjustAutoResExpAsWorked = (bool)element.Attribute("UnjustAutoResExpAsWorked"),
WageMultiply = (string)element.Attribute("WageMultiply"),
Type = (string)element.Attribute("Type"),
VisibleToUser = (bool)element.Attribute("VisibleToUser"),
CustomerId = _customerId,
};
_db.PayCodes.Add(payCode);
_db.SaveChanges();
}
New Code
I have written some code to interate through the xml file and pull out the names of the attributes - Code Below (Also works)
var xmlDoc = LoadXmlFileIntoStream("WSAPayCode.xml");
var elementCollection = ExtractDescendants(xmlDoc, "WSAPayCode");
var nodeAttributes = xmlDoc.Descendants("WSAPayCode").Select(x => x.Attributes());
foreach (var attrs in nodeAttributes)
{
var _attribute = "";
foreach (var attr in attrs)
{
// This successfully reads through each attribute and pulls out the name of the attribut
_attribute = attr.Name.ToString();
}
}
Problem I would like to solve
What I would like to do now is instantiate an object and iterate through the attribute names and save the values to the corresponding property in the object. i.e. replace the OLD code with something that dynamically assigns the values to the object properties.
I would check into using the XML Serializers / Deserializers. On your class, you have provide attributes as to whether the property is an element or attribute, and then let it handle the rest of it for you.
You could set the attributes to match what the XML document is providing, such as if the name is an element, or attribute, etc.
For example:
[XmlRoot("PayCode")]
public class PayCode
{
[XmlElement("Name")
public string Name { get; set;}
....
}
Then, to deserialize to your object:
XmlSerializer serializer = new
XmlSerializer(typeof(PayCode));
FileStream fs = new FileStream(filename, FileMode.Open);
XmlReader reader = XmlReader.Create(fs);
PayCode payCode = (PayCode)serializer.Deserialize(reader);
I have a library that contains a .NET type. The library has its own configuration (annotations etc) for serializing the type to XML, and I do not have the source code.
No matter what I do, I could not manage to add the prefix I want to add to the root element of the output XML. Using XmlSerializerNamespaces made no difference. Here is a snippet that shows my code at the moment:
var comp = row[0] as LibraryType;
var ser = new XmlSerializer(comp.GetType());
var strWriter = new StringWriter();
var xmlWriter = XmlWriter.Create(strWriter);
ser.Serialize(xmlWriter, comp);
string serXml = strWriter.ToString();
Is there a way in configure XMLSerializer to create an xlm output for root such as
<lt:LibraryType ....
instead of the current
<LibraryType .....
I'm getting ?
Lets say that your library type looks like
public class Foo
{
public int i { get; set; }
}
public class Bar
{
public Foo Foo { get; set; }
}
then serialization should look like
var comp = new Bar {Foo = new Foo()};
var overrides = new XmlAttributeOverrides();
overrides.Add(typeof (Bar), new XmlAttributes {XmlRoot = new XmlRootAttribute {Namespace = "http://tempuri.org"}});
// in case you want to remove prefix from members
var emptyNsAttribute = new XmlAttributes();
emptyNsAttribute.XmlElements.Add(new XmlElementAttribute { Namespace = "" });
overrides.Add(typeof(Bar), "Foo", emptyNsAttribute);
// if you actual library type contains more members, then you have to list all of them
var ser = new XmlSerializer(comp.GetType(), overrides);
var strWriter = new StringWriter();
var xmlWriter = XmlWriter.Create(strWriter);
var ns = new XmlSerializerNamespaces();
ns.Add("lt", "http://tempuri.org");
ser.Serialize(xmlWriter, comp, ns);
string serXml = strWriter.ToString();
and the output will be
<?xml version="1.0" encoding="utf-16"?><lt:Bar xmlns:lt="http://tempuri.org"><Foo><i>0</i></Foo></lt:Bar>
It seems I don't understand how I can get a value from a collection inside a document. I am using mongoDB in C#.
Here is my code:
var jimi = new Document();
jimi["Firstname"] = "Jimi";
jimi["Lastname"] = "James";
jimi["Pets"] = new[]
{
new Document().Append("Type", "Cat").Append("Name", "Fluffy"),
new Document().Append("Type", "Dog").Append("Name", "Barky"),
new Document().Append("Type", "Gorilla").Append("Name", "Bananas"),
};
test.Insert(jimi);
var query = new Document().Append("Pets.Type","Cat");
So my query will look for the pet cat. But I am not sure how I can get the name of my cat. I tried a few things but I mostly get the whole document back.
Thanks in advance,
Pickels
This isn't as elegant as I'd like as I'm still learning about MongoDB myself but it does show you one way to get the property you wanted.
[TestFixture]
public class When_working_with_nested_documents
{
[Test]
public void Should_be_able_to_fetch_properties_of_nested_objects()
{
var mongo = new Mongo();
mongo.Connect();
var db = mongo.getDB("tests");
var people = db.GetCollection("people");
var jimi = new Document();
jimi["Firstname"] = "Jimi";
jimi["Lastname"] = "James";
jimi["Pets"] = new[]
{
new Document().Append("Type", "Cat").Append("Name", "Fluffy"),
new Document().Append("Type", "Dog").Append("Name", "Barky"),
new Document().Append("Type", "Gorilla").Append("Name", "Bananas"),
};
people.Insert(jimi);
var query = new Document();
query["Pets.Type"] = "Cat";
var personResult = people.FindOne(query);
Assert.IsNotNull(personResult);
var petsResult = (Document[])personResult["Pets"];
var pet = petsResult.FindOne("Type", "Cat");
Assert.IsNotNull(pet);
Assert.AreEqual("Fluffy", pet["Name"]);
}
}
public static class DocumentExtensions
{
public static Document FindOne(this Document[] documents, string key, string value)
{
foreach(var document in documents)
{
var v = document[key];
if (v != null && v.Equals(value))
{
return document;
}
}
return null;
}
}