JSON.NET XML to JSon - c#

whilst trying to work on something else, i stumbled across JSON.NET, and have a quick question regarding the results.
I have a XML Field in sql, which i return in a data reader, I then run this through the following:
XmlDocument doc = new XmlDocument();
doc.LoadXml(rdr.GetString(0));
en.Add(JsonConvert.SerializeXmlNode(doc));
en is a List as there could be many rows returns. the JSON that is created is as follows with real data modified but the structure intact:
"{\"Entity\":{\"#xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"#xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"AKA\":{\"string\":[\"Name 1\",\"Name 2\"]},\"Countries\":{\"string\":[\"UK\",\"US\"]},\"IdentNumbers\":{\"string\":[\"Date Set 2\",\"Data Set 1\",\"Data Set 3\",\"Data Set 4\"]},\"PercentageMatch\":\"94\"}}"
So if there were 3 entries then msg.d would contain three values as can be seen from FireBug output below
How do i loop through this information on the client side, and present it in a table?
EDIT
So for the table layout. Any single item needs to have a heading and its associated value, for any items that have one or more value, then i need the table to have a single heading with each item on a new line. Something similiar to this:
Heading 1
Single Item Value
Heading 2
First Item Value \n
Second Item Value
Heading 2
Single Item Value
EDIT
Ok, kind of getting to where I want it. i've produced this:
success: function (msg) {
var resultHtml = "";
$.each(msg.d, function (i, entity) {
//now entity will contain one row of data - you could access the following objects :
//entity.AKA is an array with which you could loop with
resultHtml += '<label><b>Countries:</b></label>';
resultHtml += '<text>' + entity.Countries + '</text>';
resultHtml += '<label><b>Ident:</b></label>';
resultHtml += '<text>' + entity.IdentNumbers + '</text>';
//etc
});
Which produces the output of heading in bold with the value underneath. What I know need to work out, is how to only show one instance at a time, and have pages to move through :-) Any Idea?

using $.each, maybe? Here's the syntax :
$.each(msg.d, function(i, entity) {
//now entity will contain one row of data - you could access the following objects :
//entity.AKA is an array with which you could loop with
//entity.Countries
//entity.IdentNumbers
//etc
});
Then you could construct that table in your each loop. If you give me more info on how you'd want to set up your table (the format), we could help you on that.
Here's a fiddle for you. Resize the output window and check the table : http://jsfiddle.net/hungerpain/9KBDg/

Related

How to get the Columns from a WebMatrix Query?

The title is pretty self-explanitory, and it seems like it should be an easy task, but everything I've tried has not worked:
Here's my code, which works fine, but the table is variable, so I need to know the Columns it comes back with:
var data = db.Query("SELECT * FROM " + Table);
Here's a list of techniques I've tried:
data.GetType().GetProperties().ToList();
// prints 'Int32 Count' and 'System.Object Item [Int32]'
data.GetDynamicMemberNames()
// Error: '...IEnumerable<dynamic> does not have a definition for GetDynamicMemberNames'
// I also tried using System.Linq and System.Dynamic
I could also iterate through a loop, but there's got to be a more elegant way, right?
I'd like to end up with a List<String> of the Column Names.
List<String> cols = data.First().Columns;
It turns out the Columns Propery is an IList<string> type.
However, it is a property of an individual row of the data result (a row is a DynamicRecord data type), so it is unfortunately inaccessible from the result Object (data in my example). To access it, you need to get a single row, and .First() seems to be a pretty easy way to do that.
Here's my whole code in case anyone needs it:
WebMatrix.Data.Database db = new WebMatrix.Data.Database();
db.Open("ConnectionString");
var data = db.Query("SELECT * FROM " + Table);
List<String> cols = data.First().Columns;

JQuery MVC collection name attributes

I have a table, and I've dynamically added / removed rows from it.
The table contains fields that will be posted back as a collection to MVC.
In this scenario updating the table with jquery means I up with collections that contain incomplete collections for example ...
function add() {
$.ajax({
url: "GetRow",
type: 'post',
dataType: 'html',
timeout: 30000,
data: {
RowIndex: otherRows.length,
"Item.Property1": $("option:selected", dropDown).text(),
"Item.Property2": $("option:selected", dropDown).val()
},
success: function (result) {
var newRow = $(result);
tableBody.append(newRow);
}
});
}
This function makes an ajax call to go get an mvc action result that returns the result of a row at the given index and additionally sets some default values from a drop down on my page.
Now lets assume I have a similar function called "delete" in which using jquery i remove a row and at this point the table has 3 rows (ignoring the header row of course), and the row i'm removing is the middle row.
this means the fields in my rows end up looking something like this ...
//Row 1:
<input type="text" name="SomeCollection[0].Property1" />
//Row 2:
Nothing, deleted of course
//Row 3:
<input type="text" name="SomeCollection[2].Property1" />
So if i now do a postback, because of the inconsistent id range, the MVC model binder will only bind item 1 for me and item 2 (actually item 3 prior to the client side delete) is not mapped.
The idea is that i want my server logic to do a very simple "if the id for an item in my collection is not in the post data, delete it from the database", this way all the collection manipulation can be entirely client side in save on constant postbacks on this very heavy page.
So I started putting a function together in jquery to fix the problem ...
function updateNames(table) {
var rows = $("tr", table);
var index = 0;
rows.each(function () {
var inputFields = $("input");
inputFields.each(function (){
//replace name="bla[<any number>].Anything" with
// name="bla[" + index + "].Anything"
});
index++;
});
}
So my question is ... How do i say to jquery "replace [] in the name attribute with [index]"?
I know this wont solve the problem of nested collections / other such complex scenarios but for that once i have this function solved I can always extend it later and my requirements are not that involved yet.
EDIT:
Some additional detail on my current thought pattern ... good or bad?
if i grab the name attribute value and "walk the chars" until i find the first "[" and the next "]" then replace everything in between, it should solve my problem, but this type of thing on IE probably slow as hell.
Anyone got a neat "just call this clever function" type answer? (if there is one).
EDIT 2:
Wow I really gotta look harder ... what a dumbass i feel like right now for 2 reasons (not looking and regex is an obvious solution here)
JQuery: how to replace all between certain characters?
if i can figure out the right regex i've got my solution (maybe that's the question I should have asked as i'm constantly annoyed by the crazyness of regex).
But the power of a regex cannot be under estimated :)
This should work for you:
function updateNames(table) {
var rows = $("tr", table);
var index = 0;
rows.each(function () {
var inputFields = $(this).find("input");
inputFields.each(function (){
var currentName = $(this).attr("name");
$(this).attr("name", currentName.replace(/\[(.*?)\]/, '['+index+']'));
});
index++;
});
}
If there are multiple inputs inside each row and you just want to update one then consider using the 'starts with' jQuery selector: http://api.jquery.com/attribute-starts-with-selector/.
Though you've already got a resolution, I thought a working demo of how one might implement this functionality from the ground up might be useful.
Supposing you have a button with a class of delete on each row, you can achieve this with the following:
$('.delete').click(function(e) {
// Get table body and rows
var body = $(this).closest('tbody');
// Remove current row
$(this).closest('tr').remove();
// Get new set of rows from table body
var rows = body.find('tr')
// Update all indeces in rows
var re = new RegExp(/\[[0-9]+\]/);
var index = 0;
rows.each(function () {
$(this).find('input').each(function (e) {
var input = $(this).attr('name');
if (input) {
$(this).attr('name', input.replace(re, '['+index+']'));
}
});
index ++;
});
});
This should delete the row and update all indeces for every input in the remaining rows so that they increment properly again (and thus will be bound properly by the model binder). Additionally, it should be restricted to the current table. Here it is in action.

Saving a reordered List item from an MVC View Model

I have a view model which binds to a 'TreasureHuntDetails' object, which contains a list of clues. Here's part of the data model for it.
public TreasureHuntDetails()
{
Clues = new List<Clue>();
}
[Key]
public int TreasureHuntId { get; set; }
public List<Clue> Clues { get; set; }
On the page, I have a table. A foreach loop iterates through the list of clues to add them to the table, e.g.
#for (int i = 0; i < Model.Clues.Count; i++)
The table elements inside the for loop are quite large, but here's an example of one of the table element columns:
<td>#Html.DisplayFor(m => Model.Clues[i].Location)</td>
All well and good so far. Then I'm using JQuery UI to allow the items of the table to be reordered using drag and drop, like this:
<script type="text/javascript">
$(document).ready(function()
{
$("#clueTable tbody").sortable().disableSelection();
});
</script>
All well and good, I can drag and drop the elements.
The problem is that I don't know how to save the new order of elements and save them back to the database.
The first thing I tried was simply passing the list of clues to a controller method, but I found that once the list of clues reached the controller method, it was always null.
For example:
#Url.Action("ViewCluePage", #Model.Clues)
Even if I send the whole #Model, list of clues within is always null. Removing the new list instantiation from the constructor of the data model didn't solve this problem.
Another thing I tried was wrapping the whole table into a HTML form, but still the list of clues remains null.
So basically, this question is really two questions:
1) Why is the list of clues always null after sending the model object to a controller.
2) How to save the new order of the list of items?
UPDATE: As per suggestion by #recursive, I see where I made an error when trying to submit the clue elements to the HTML form.
I used this outside the for loop which iterated over the clue elements:
#Html.HiddenFor(m => m.Clues)
I had to add the HiddenFor lines inside of the for loop (for each clue item), and for EACH property of the clue item, e.g.
#Html.HiddenFor(m => m.Clues[i].Id)
So that would be one step forward to be able to get the list items sent to the controller, but I think I still need code that will reflect the new order of the clue items when sent to the controller. Currently, on rearranging the order of the elements on screen using the JQuery sortable() method, this doesn't change the order of the elements as they are stored in the data model binded to the view (#Model.Clues).
1) As #resursive said in his comment, you need to have hidden elements on the page that map to properties in your Clue class.
2) As for persisting the order of clues, you'll need to add a column to your database that holds the position of each clue in the list and add the position property to your class. So your class would need to include
public int Position {get;set;}
which should pull from the database when the page is created. Then just before rendering the page, you should reorder the clue list based on the Position variable.
Edit: Use jquery's sortable attribute. Check out this thread for reference. In the stop drag event (or right before your submit), loop through each of your draggable objects and set the value of each of the hidden Position properties of your objects.
var positionIndex = 0;
$('.draggableObjectClass).each(function () {
$(this).find('input[id$=_Position]').val(positionIndex++);
});
but I think I still need code that will reflect the new order of the clue items when sent to the controller.
You won't, as you are now iterating over them in a for loop, they will be indexed in the order that you sent them to the view. Your order must already be maintained.
Taking advice from the answers posted here already, I came up with the following solution.
With already having this method in place to implement the drag and drop reordering of the UI elements,
$(document).ready(function()
{
$("#clueTable tbody").sortable().disableSelection();
});
I needed a way to be able read the in the new order of items and send it to the MVC controller. To do this I used the Razor #Html.AttributeEncode method to write the Id's of each item to a column on each row of the table, like this:
<td class="Ids" id="#Html.AttributeEncode(Model.Clues[i].Id)">#{var number = i + 1; #number}</td>
(This is wrapped around a for loop which iterates through the list of items.)
Then, I created the following Javascript function, which is invoked from a 'SaveNewOrder' button I placed above my table of elements (the user presses this once they have finished reordering the items on the table):
function getNewOrder()
{
var positions = new Array();
for (var i = 0; i < $('.Ids').length; i++)
{
positions[i] = $('.Ids')[i].id;
}
$.ajax(
{
type: "POST",
url: "#Url.Action("ReorderClues", "Clues")",
data:{ treasureHuntDetails: $("form").serialize(), ids: JSON.stringify(positions) }
contentType:'application/json'
}).done(function()
{
window.location.href = '#Url.Action("Clues", Model)';
}).
}
What this is does is reads the Id elements from each of the table items, and writes them into the array - so this array contains the NEW order of Id's. The data model containing the items doesn't change after reordering the table elements, hence why this was necessary.
It then uses a JQuery Ajax method to invoke a 'ReOrderClues' method on my 'Clues' MVC controller, passing a serialised version of the data model (containing a list of the clue items in the original order) and an array containing a list of the clue Id's in the new order. When the result is returned from the controller (.done), I invoke a controller which refreshes the page elements.
So rather than having to maintain a position value associated with each clue (which would involve significant refactoring elsewhere in the code), what I'm doing is swapping the contents of the clues around to reflect the new order, but keeping the Id's in the same position.
This is how I achieved that using an MVC Controller:
public ActionResult ReorderClues(TreasureHuntDetails treasureHuntDetails, int[] ids)
{
using (var db = new TreasureHuntDB())
{
var clues = treasureHuntDetails.Clues;
var newClues = NewOrderList(clues, ids);
// Save the changes of each clue
for (var i = 0; i < newClues.Count;i++ )
{
db.Entry(clues[i]).CurrentValues.SetValues(newClues[i]);
db.SaveChanges();
}
treasureHuntDetails.Clues = newClues;
TempData["Success"] = "Clues reordered";
}
return RedirectToAction("Clues", treasureHuntDetails);
}
public List<Clue> NewOrderList(List<Clue> clues, int[] ids)
{
var newClueOrder = new List<Clue>();
// For each ID in the given order
for (var i = 0; i < ids.Length; i++)
{
// Get the original clue that matches the given ID
var clue = clues.First(clue1 => clue1.Id == ids[i]);
var newClue = Clue.Clone(clue);
// Add the clue to the new list.
newClueOrder.Add(newClue);
// Retain the ID of the clue
newClueOrder[i].Id = clues[newClueOrder.Count - 1].Id;
}
return newClueOrder;
}
In the above code snippet, TreasureHuntDB is my Entity Framework database context.

Retrieve "row pairs" from Excel

I am trying to retrieve data from an Excel spreadsheet using C#. The data in the spreadsheet has the following characteristics:
no column names are assigned
the rows can have varying column lengths
some rows are metadata, and these rows label the content of the columns in the next row
Therefore, the objects I need to construct will always have their name in the very first column, and its parameters are contained in the next columns. It is important that the parameter names are retrieved from the row above. An example:
row1|---------|FirstName|Surname|
row2|---Person|Bob------|Bloggs-|
row3|---------|---------|-------|
row4|---------|Make-----|Model--|
row5|------Car|Toyota---|Prius--|
So unfortunately the data is heterogeneous, and the only way to determine what rows "belong together" is to check whether the first column in the row is empty. If it is, then read all data in the row, and check which parameter names apply by checking the row above.
At first I thought the straightforward approach would be to simply loop through
1) the dataset containing all sheets, then
2) the datatables (i.e. sheets) and
3) the row.
However, I found that trying to extract this data with nested loops and if statements results in horrible, unreadable and inflexible code.
Is there a way to do this in LINQ ? I had a look at this article to start by filtering the empty rows between data but didn't really get anywhere. Could someone point me in the right direction with a few code snippets please ?
Thanks in advance !
hiro
I see that you've already accepted the answer, but I think that more generic solution is possible - using reflection.
Let say you got your data as a List<string[]> where each element in the list is an array of string with all cells from corresponding row.
List<string[]> data;
data = LoadData();
var results = new List<object>();
string[] headerRow;
var en = data.GetEnumerator();
while(en.MoveNext())
{
var row = en.Current;
if(string.IsNullOrEmpty(row[0]))
{
headerRow = row.Skip(1).ToArray();
}
else
{
Type objType = Type.GetType(row[0]);
object newItem = Activator.CreateInstance(objType);
for(int i = 0; i < headerRow.Length; i++)
{
objType.GetProperty(headerRow[i]).SetValue(newItem, row[i+1]);
}
results.Add(newItem);
}
}

Get text above table MS Word

This one is probably a little stupid, but I really need it. I have document with 5 tables each table has a heading. heading is a regular text with no special styling, nothing. I need to extract data from those tables + plus header.
Currently, using MS interop I was able to iterate through each cell of each table using something like this:
app.Tables[1].Cell(2, 2).Range.Text;
But now I'm struggling on trying to figure out how to get the text right above the table.
Here's a screenshot:
For the first table I need to get "I NEED THIS TEXT" and for secnd table i need to get: "And this one also please"
So, basically I need last paragraph before each table. Any suggestions on how to do this?
Mellamokb in his answer gave me a hint and a good example of how to search in paragraphs. While implementing his solution I came across function "Previous" that does exactly what we need. Here's how to use it:
wd.Tables[1].Cell(1, 1).Range.Previous(WdUnits.wdParagraph, 2).Text;
Previous accepts two parameters. First - Unit you want to find from this list: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.wdunits.aspx
and second parameter is how many units you want to count back. In my case 2 worked. It looked like it should be because it is right before the table, but with one, I got strange special character: ♀ which looks like female indicator.
You might try something along the lines of this. I compare the paragraphs to the first cell of the table, and when there's a match, grab the previous paragraph as the table header. Of course this only works if the first cell of the table contains a unique paragraph that would not be found in another place in the document:
var tIndex = 1;
var tCount = oDoc.Tables.Count;
var tblData = oDoc.Tables[tIndex].Cell(1, 1).Range.Text;
var pCount = oDoc.Paragraphs.Count;
var prevPara = "";
for (var i = 1; i <= pCount; i++) {
var para = oDoc.Paragraphs[i];
var paraData = para.Range.Text;
if (paraData == tblData) {
// this paragraph is at the beginning of the table, so grab previous paragraph
Console.WriteLine("Header: " + prevPara);
tIndex++;
if (tIndex <= tCount)
tblData = oDoc.Tables[tIndex].Cell(1, 1).Range.Text;
else
break;
}
prevPara = paraData;
}
Sample Output:
Header: I NEED THIS TEXT
Header: AND THIS ONE also please

Categories