I'm a student working on a lab that parses a pseudo XML file(basically coded our own parser) for data, stores the retrieved elements and data values, and displays (next lab will be adding "add,change,delete" functionality)
I was thinking about holding this read in information in some sort of multidimensional List due to it being dynamic by default. The other suggestion I've read over some other questions here at SO is to make a "parent node" class, and just store that in an array.
The problem I have is that at code time there is no way to know for sure how many child nodes a parent node will have. It could be --
<parent>
<child1>data value</child1>
<child2>data value</child2>
...etc
</parent>
or
<parent>
<child1data value</child1>
</parent>
I can't really think how I could code a class to have an unknown amount of variables.
Why not just use a List<List<T>>? Or maybe a Dictionary<string, List<T>>, assuming your parent nodes have unique identifiers?
You can keep a list of nodes or a dictionary of nodes if the nodes are unique in some way.
.NET collections are inherently dynamic. You don't need to know in advance how many items your collection will hold. A collection of your own class "parent" would work. Each parent class itself would implement a collection of "children". You can define them to be anything you want.
Even better though would be to make your class serializable from the get go, so that when you save it to an XML file it's already in a properly formatted XML structure. Reading in that data would require deserialization and it would populate everything for you. Check this out.
You should manage by your self but just think, you have parent as root and parent has list of child. Where is problem ? :)
Related
My initial thought was to create an Umbraco Relation and associate the Umbraco Member to the Nested Content node. Sadly, I found this form post asking a similar question and as you can see in Matt Bailsford's first response:
Unfortunately nested content can't have an ID value as they don't truely exist
I did find the issue/feature that was discussed in the forum post; however, it just adds parent information to the DetachedPublishedContent object and doesn't solve my issue. After reading the form post and the conversations of Hendy Racher, Matt Bailsford and Lee Kelleher in the github pull request, I still don't understand why Nested Content doesn't create a node in Umbraco.
So basically I need the Nested Content nodes to be created as Umbraco nodes and then stored as a JSON string in the property field. There are a few ways that I see this could be accomplished:
Create a Custom Property Editor for Umbraco Backoffice - I would start with a copy of Nested Content and add code to create the node and attach it before saving the node as a JSON string.
Use the Umbraco Multinode Treepicker control - This control was suggested by Hendy and Jeavon in this forum post as a way to allow a user to select multiple content nodes. Unfortunately going this route would require the user to create the "nested content" nodes first. Then they could associate those "nested content" nodes with the original node. We really like the user experience of the Nested Content control where it allows you to create nodes dynamically in the property editor.
Find a way to associate the Member to the "Nested Content" node - This option would require that I store an association between the top node and it's respective "nested content" node to a Member in Umbraco. There are two issues that come to mind when trying to go this route:
How should I associate the "nested content" node to the Member in a standard Umbraco way? - I immediately think of creating a link table in the database but, in my understanding, that is not the standard Umbraco way. I am still fuzzy about the best way to do this inside Umbraco.
Is there a way to uniquely identify the "nested content" node? - I realize there is a sort order value being set according to the pull request I found above but if the user reorders the nested content items will it change the "nested content" node to member association?
At this point, I am leaning towards going with option 1, but I wonder if option 3 is a better direction. In reality, I don't believe this is a new problem that someone hasn't already solved, and I hate to create another custom property editor if there is one just like it out there already.
So if you know of a better way to solve this problem please let me know.
The problem is - as you mention it - that Nested Content nodes aren't really real nodes. I don't think the right way to solve your problem is to try hacking Nested Content into doing something it really wasn't created to do.
The problem about creating nodes and also having references to them on the Nested Content node is that essentially every node in Umbraco needs to "live" somewhere.
You could choose to say that a node lives under the parent it is nested into, but how would you then differentiate between nested nodes and actual child nodes - this would require another hack as it is really working around how nodes are meant to be structured and handled in the Umbraco core.
Even if you did manage to get this working, I suspect you would have a lot to deal with to actually make it work as good as Nested Content currently does:
You would have somehow wrap every single node in the Nested Content editor into a object to be able to store meta data like the node ID it is connected to and the sortOrder when reordering all of the nested content nodes you have on there.
(edit: I think it actually already stores some sort of wrapper object here, but you would have to change the logic in here to actually handle a reference to another node instead of just deserializing json stored here, as a node)
You would also have to manually hook into events making sure the actual edits you do while on the parent node actually ends up being persisted to the nested nodes.
Deleting a nested content node, or a parent that has any nested nodes - you would have to handle deleting any orphaned nodes.
There's most likely a lot of stuff I've missed but my point is - you will have a lot of trouble trying to do this.
I think you should consider another approach if you really need to do this:
It would be possible to create a picker similar to a normal node picker, that simply allows you to browse through nodes as a normal picker would do. When you pick a node, instead of just selecting it, it should then fetch the nested content nodes and show those in the UI.
There's however the little quirk that you could essentially be having multiple properties storing each their set of nested content nodes on one single content item - so you would need some nice way of handling this in the UI.
When you select one or multiple of the nested nodes, what your picker would store would be something similar to [guid-of-the-real-node]_[propertyAlias]_[guid-of-nested-content-item].
I am not certain if Nested Content ever got the GUID unique ID/key feature implemented - Matt and I discussed it some time last year and we tried adding it in, in a custom build I needed for a project. If it isn't there I would suggest you ask Matt if he can get that in. It was essentially just giving each nested content item a "fake" unique ID (GUID) that you could use to identify it from other nested content items stored in the property. (You would have to ask Matt about the status of this)
Doing this would allow you to (on your member) have a reference that you lets you find the actual content node, then the property where the content is stored, and lastly the actual nested content node you have picked.
You should however note that this is very prone to breaking and needs a lot of null handling:
If you change the property alias of the property you are storing nested content in on the parent, it will lose the reference.
If you delete the content item storing the nested items, the picked items no longer exist and you have a missing reference in the picker on your member (needs null handling)
If you delete a nested content item - same as above. You have a missing reference in your picker.
Apart from the solution above, I don't really see another way of doing this currently with the requirements you have.
I am creating a Web API service that acts as a facade for my clients to a more complex messaging API on the backend. The .XSD that represents the calls I need to make to the backend API is obviously not something I want them to understand. My goal is to flatten out the required elements in a ViewModel class that can be used by the client. My POST might be something like below:
public HttpResponseMessage Post(FlattenedViewModel flattenedViewModel)
{
}
The idea of the flattened view model is to prevent my clients from having to understand any complex structuring of data to call my API. It's a lot easier to submit this (could be JSON or XML):
<PersonFirstName>John</PersonFirstName>
<PersonLastName>Smith</PersonLastName>
<PersonPhone>123-456-7890</PersonPhone>
than this:
<Person>
<Name>
<FirstName>John</FirstName>
<LastName>Smith</LastName>
</Name>
<Communication>
<Type>
<Phone>123-456-7890</Phone>
</Type>
</Communication>
</Person>
I understand creating the class structure to represent the 2nd example is not difficult and easy for all of us to understand. However, my real .XSD is about 50x this example. My goal is to provide an easier interface and ability to have a flattened view, so please use that as a constraint of this question. Imagine it like a user was entering data on a form and pressed submit; a form is like a flattened view of data to be entered.
The hurdles I am encountering are the following:
Having a node that can repeat a finite set of times is solvable. However, nodes with the following constraint on the .xsd: maxOccurs="unbounded" do not appear to be initially doable with a flattened view. Is there another way of doing this so I don't have to introduce a collection? Or can I introduce a collection but still allow the user to not have to understand a complex structure (like my 1st example)? Please provide an example of what that would look like if possible.
I have node names that are repeated among different parts of the .xsd but are unrelated. For example the node ID or Date. My solution is to append the parent node name to the value to create a property like SubmitDate or PersonID. The issue I now have is my ViewModel class property names don't match the ones of my entities that must be mapped to in the domain model. I'm using ValueInjecter, so is there any type of streamlined way I can still map properties to other classes that have different names (i.e. annotation or something)?
Any help is appreciated, thank you!
I believe the answer lies in creating custom injections for ValueInjector to use and then simply making a call to 'InjectFrom' to invoke them...
_person.InjectFrom<CustomPersonInjection>(flattenedViewModel);
I had a quick look around for some specific examples that might help you but could find anything within a reasonable time frame (they're out there though, google 'valueinjecter custom injections').
Here are some links to get you started:
Deep Cloning example: http://valueinjecter.codeplex.com/wikipage?title=Deep%20Cloning&referringTitle=Home
Custom Convention Injection: Using ValueInjecter to map between objects with different property names
I would like to provide the user a visual DOM like representation of an XML structure (here a completed infopath form) and allow them to specify which elements of the xml data they want to map to a statically compiled object.
As an example, the user has an infopath form that allows them to enter a sales deal, they fill it out and submit, the app should allow them to see the structure of the data in the infopath form (in a friendly, treeview kind of way) and specify how it should map to a static representation of the sales deal (think of a row that might go in the "Deals" table).
The Infopath forms (xml source) are not controlled by me.
I'm looking for suggestions on how to display the treeview of the XML and allow interaction with it to specify the mapping (possibly drag and drop?).
This will be in a wpf application (I know I'll have to host the infopath control in a forms host since it is not wpf) written in c#, and we would prefer to use .Net elements provided by Microsoft or open source software.
Edit: As a more thorough example, let's say there is an infopath form that results in xml that looks something like:
<Deal id="1" dateBooked="2011-01-01" term="24" language="en-us">
<Salesman>Jim Flowers</Salesman>
<FinancedAmount>55000.00</FinancedAmount>
<Items>
<Item id="1" quantity="10" unitPrice="10000.00">Tractor</Item>
<Item id="2" quantity="1" unitPrice="5000.00">Spare Blade</Item>
</Items>
<Notes>
<Note dateAdded="2010-09-20">Customer needs a spare blade</Note>
<Note dateAdded="2010-12-31">Customer wants to sign the deal on new year's day, I find this odd...</Note>
</Deal>
I want the user to, at run time and in an intuitive manner (the user will not know xpath...) map specific nodes of a treeview of this document to a field on my "Deal" object. So, the Deal object might have an id, salesman, amount, items collection, etc. that need to be populated but the notes and some other data are ignored, and the forms will not be the same (info path is providing configurable forms for the user to get data into the system however they want) or named in any consistent matter. The user is specifying the mapping.
Andreas's solution looks like it would be a good first step. Looks like for your input it would need to recurse into attributes of the nodes as well tho.
My description of your plan would be:
Build a control that shows all the data (Andreas uses a TreeView)
You'd probably want to show the Name and the Value for each
Build a similar control for the Object you are loading into
Setup events to build the mapping
You mentioned dragging between them
Or if they are both checkbox trees maybe have them check one in the Xml tree, then one in the Object tree and reset both, building a list of the mappings created
Finally use that mapping list to fill the object
I don't see any simple way to do it, its a lot of work and a lot of it depends on the specifics of the implementation so I can't just give you code that can do it.
How I think I might do it to get it working quickly:
Recurse through the xml generating xpaths as you go for each and every value
Load all of those xpaths and the names and values they represent into a table to be displayed to the user
With columns for "Name", "Value", "xpath"-hidden, "Load Into Property"-dropdown
Build a drop down listing every property in your object, have that in a column in the table displayed to the user
Basically I believe you need to break this down into smaller steps, and search for help on each specific step.
I'd go the simpliest way possible - create a treeview from the given xml and add a checkbox to each node. When the user clicks the "OK" (or whatever) button, you iterate all checkboxes that are checked and build your object.
Creating a treeview from a xml is rather simple - this should work (i did not test it however!)
public static class TreeViewExtensions
{
public static void LoadXml(this TreeView treeview, XmlDocument doc)
{
treeview.Nodes.Clear();
RecursiveImport(treeview.Nodes, doc.ChildNodes);
}
private static void RecursiveImport(TreeNodeCollection tvNodes, XmlNodeList xmlNodes)
{
TreeNode tvNode;
foreach (XmlNode xmlNode in xmlNodes)
{
tvNode = new TreeNode(xmlNode.Name);
if (xmlNode.ChildNodes.Count > 0)
RecursiveImport(tvNode.Nodes, xmlNode.ChildNodes);
tvNodes.Add(tvNode);
}
}
}
Edit: Well basically, you could list all xml fields in a listbox, and all fields of your object in another. When a user drag & drop's 1 field to your object's listbox, you'd need to save this relationship in another object.
I'm not familiar with wpf but this article seems pretty good - http://www.codeproject.com/KB/dotnet/csdragndrop01.aspx
The "link" Enumeration type looks pretty promising for what you try to achieve.
I like Microsoft's Windows Forms tree-view object model. It has the tree, nodes, children collection, parent, prev, next (sibling), etc. and search function. However I'm looking for the same object model with no UI - simply tree object model.
Does C# have this kind of model or do I have to implement it myself?
C# is a programming language. It does not have object models.
You may be asking whether the .NET Framework has a built-in "tree" class. It does not. You can build your own using the generic collection classes like LinkedList<T> and List<T>.
You could always use XML and the XML namespaces. It's got all the things you requested. Start with and XMLDocument and keep added XMLNodes and adding XMLNodes to the XMLNodes for children. Then you can use xpath queries to retrieve nodes.
An XmlDocument object is the closest match I can think of to your requirements. It supports parent, child, previous, next, sibling, etc. You can also use XPath to query the tree and return a specific node or sets of nodes. Also, because it's Xml you can easily import and export the data to/from a text file.
I suggest you read about binary trees on MSDN. It will teach you how to model tree data structures in code.
Good luck.
I'm wondering what the best practices are for storing a relational data structure in XML. Particulary, I am wondering about best practices for enforcing node order. For example, say I have three objects: School, Course, and Student, which are defined as follows:
class School
{
List<Course> Courses;
List<Student> Students;
}
class Course
{
string Number;
string Description;
}
class Student
{
string Name;
List<Course> EnrolledIn;
}
I would store such a data structure in XML like so:
<School>
<Courses>
<Course Number="ENGL 101" Description="English I" />
<Course Number="CHEM 102" Description="General Inorganic Chemistry" />
<Course Number="MATH 103" Description="Trigonometry" />
</Courses>
<Students>
<Student Name="Jack">
<EnrolledIn>
<Course Number="CHEM 102" />
<Course Number="MATH 103" />
</EnrolledIn>
</Student>
<Student Name="Jill">
<EnrolledIn>
<Course Number="ENGL 101" />
<Course Number="MATH 103" />
</EnrolledIn>
</Student>
</Students>
</School>
With the XML ordered this way, I can parse Courses first. Then, when I parse Students, I can look up each Course listed in EnrolledIn (by its Number) in the School.Courses list. This will give me an object reference to add to the EnrolledIn list in Student. If Students, however, comes before Courses, such a lookup to get a object reference is not possible. (Since School.Courses has not yet been populated.)
So what are the best practices for storing relational data in XML?
- Should I enforce that Courses must always come before Students?
- Should I tolerate any ordering and create a stub Course object whenever I encounter one I have not yet seen? (To be expanded when the definition of the Course is eventually reached later.)
- Is there some other way I should be persisting/loading my objects to/from XML? (I am currently implementing Save and Load methods on all my business objects and doing all this manually using System.Xml.XmlDocument and its associated classes.)
I am used to working with relational data out of SQL, but this is my first experience trying to store a non-trivial relational data structure in XML. Any advice you can provide as to how I should proceed would be greatly appreciated.
Don't think in SQL or relational when working with XML, because there are no order constraints.
You can however query using XPath to any portion of the XML document at any time. You want the courses first, then "//Courses/Course". You want the students enrollments next, then "//Students/Student/EnrolledIn/Course".
The bottom line being... just because XML is stored in a file, don't get caught thinking all your accesses are serial.
I posted a separate question, "Can XPath do a foreign key lookup across two subtrees of an XML?", in order to clarify my position. The solution shows how you can use XPath to make relational queries against XML data.
While you can specify order of child elements using a <xsd:sequence>, by requiring child objects to come in specific order you make your system less flexible (i.e., harder to update using notepad).
Best thing to do is to parse out all your data, then perform what actions you need to do. Don't act during the parse.
Obviously, the design of the XML and the data behind it precludes serializing a single POCO to XML. You need to control the serialization and deserialization logic in order to unhook and re-hook objects together.
I'd suggest creating a custom serializer that builds the xml representation of this object graph. It can thereby control not only the order of serialization, but also handle situations where nodes aren't in the expected order. You could do other things such as adding custom attributes to use for linking objects together which don't exist as public properties on the objects being serialized.
Creating the xml would be as simple as iterating over your objects a few times, building up collections of XElements with the expected representation of the objects as xml. When you're done you can stitch them together into an XDocument and grab the xml from it. You can make multiple passes over the xml on the reverse side to re-create your object graph and restore all references.
Node ordering is only important if you need to do forward-only processing of the data, e.g. using an XmlReader or a SAX parser. If you're going to read the XML into a DOM before processing it (which you are if you're using XmlDocument), node order doesn't really matter. What matters more is that the XML be structured so that you can query it with XPath efficiently, i.e. without having to use "//".
If you take a look at the schema that the DataSetGenerator produces, you'll see that there's no ordering associated with the DataTable-level elements. It may be that ADO processes elements in some sequence not represented in the schema (e.g. one DataTable at a time), or it may be that ADO does forward-only processing and doesn't enforce relational constraints until the DataSet is fully read. I don't know. But it's clear that ADO doesn't couple the processing order to the document order.
(And yes, you can specify the order of child elements in an XML schema; that's what xs:sequence does. If you don't want node order to be enforced, you use an unbounded xs:choice.)
The order is not usually important in XML. In this case the Courses could come after Students. You parse the XML and then you make your queries on the entire data.
From experience, XML isn't the best to store relational data. Have you investigated YAML? Do you have the option?
If you don't, a safe way would be to have a strict DTD for the XML and enforce that way. You could also, as you suggest, keep a hash of objects created. That way if a Student creates a Course you keep that Course around for future updating when the tag is hit.
Also remember you can use XPath queries to access specific nodes directly, so you can enforce parsing of courses first regardless of position in the XML document. (making a more complete answer, thanks to dacracot)
You could also use two XML files, one for courses and a second for students. Open and parse the first before you do the second.
I's been a while, but I seem to remember doing a base collection of 'things' in one part of an xml file, and referring to them in another using the schema features keyref and refer. I found a few examples here. My apologies if this is not what you're looking for.
XML is definitely not a friendly place for relational data.
If you absolutely need to do this, then I'd recommend a funky inverted kind of logic.
In your example, you've got Schools, which offers many courses, taken by many students.
Your XML might follow as such:
<School>
<Students>
<Student Name="Jack">
<EnrolledIn>
<Course Number="CHEM 102" Description="General Inorganic Chemistry" />
<Course Number="MATH 103" Description="Trigonometry" />
</EnrolledIn>
</Student>
<Student Name="Jill">
<EnrolledIn>
<Course Number="ENGL 101" Description="English I" />
<Course Number="MATH 103" Description="Trigonometry" />
</EnrolledIn>
</Student>
</Students>
</School>
This obviously isn't the least repetitive way to do this (it's relational data!), but it's easily parse-able.