Pulling out XML values from a string in a database column - c#

I have seen various questions on this, but none seem to be working in my problem. I have an Umbraco site set up and it stores its page contents as XML in a database column. An example one is below:
Sorry for the screen grab and not the actual code, but the editor kept stripping things out.
What I would like to do ideally is either on the page in c#/Linq (have been trying to manipulate is from a string value) or within a SQL query. To be able to pull out the 'url-name', 'nodeName' and 'bodyText' fields.
Many thanks

Since the column is not defined as XML in the database, you can pull out the string and parse the text/string as an XML document:
// xml would be pulled from the DB
string xml = "<RunwayTextpage nodeName=\"Test page\" urlName=\"test-page\"><bodyText>Body Text</bodyText></RunwayTextpage>";
var doc = XDocument.Parse( xml );
string nodeName = doc.Root.Attribute( "nodeName" ).Value;
string urlName = doc.Root.Attribute( "urlName" ).Value;
string bodyText = doc.Root.Element( "bodyText" ).Value;
Another option would be to use string manipulation in the SQL query itself, but that would end up being much less maintainable whereas the above is easily understandable.

Why don't use uQuery? Don't really know your purposes, but it has a method called GetNodesByXPath that gets a collection of nodes or node from an XPath expression by querying the in memory xml cache.
It's more wise in terms of performance if your tree is large.

Related

Reading a string formatted like XML

I have a string that is written out like an XML file. An example would look like this:
string = <Employees><EmployeeId>1</EmployeeId>< ... ></Employees>
I am saving this in a table because I wanted to audit changes, but I didn't want to have multiple tables for different audits. This is because it would record changes to things other than employees. So using an XML style string in the database seemed like a good suggestion.
Now to the real business. I want to check to make sure that there were actually changes to the employee because one could go into the edit page, change nothing, and click save. As of right now, the data would write to the DB and just clutter it up with non-changed data.
I'd like to be able to check if the XML styled string that is going to be saved is on the database, so if <employees><employeeid>###</employeeid> == "changes" and then see if the whole string equals the other. Basically, check the employeeId first because that won't change, and then check the string as a whole to see if there is any difference. I would have just checked the first n numbers, but the id number could have a length of 1 to 3.
Also, because it is styled as XML, is there an easy way to convert it to read it like an XML file and check that way?
Storing arbitrary data in a column is a form of denormalization. You can't really do much with it at a database level. However, SQL Server does have an XML column type. Entity Framework doesn't support mapping to/from an XML column, so it will simply treat your XML as a standard string. With this column type, though, you can write actual SQL queries against your XML using XPath expressions.
Your best bet, then, is to type your column as XML, and then write a stored procedure that performs the query you need. You can then utilize this stored procedure with Entity Framework.
For more information on the XML column type see: https://msdn.microsoft.com/en-us/library/ms190798(SQL.90).aspx

Create XElement from invalid or partial XML String

I am working with a vendor supplied application that stores XML data as byte array in a SQL database table. I have found if the XML data is "too long" (meaning by a possible predetermined length in black box code provided by the vendor) the XML is truncated and a second record, containing the remainder of the XML data, is created.
My task is to take these "linked" records and merge them into one valid XML string. These linked records can be broken off anywhere, in the middle of an element, node, etc. There is no rhyme or reason to where the XML string is broken.
Taking the invalid XML data and loading it into an XElement causes an error "Tag has no closing tag".
I've also tried using an XmlReader and reading through each Node, based on this article as well as this msdn article. They also result in the above missing tag error.
Is there a way to take these partial xml strings and merge them? Or am I simply stuck?
The vendor application we use does perform this merge, but that code is hidden from me.
Thank you

How to move through different records in C#

I made a form that basically displays information about different vendors from an XML file that I was given. The XML file is retrieved from a class that I created, called VendorsDB.cs. On my form, I have a Previous and Next button that I want to display the next vendor or the previous vendor (Vendor1, Vendor2...) but I have no idea what method to use. I know I have to use a loop but I'm not sure as to how to code the loop. I've just started programming with C# so I'm really lost. Any help would be greatly appreciated!
Your question is missing alot of information, but what im seeing is that you need to do some work with XML.
I suggest you look into Linq To XML which enabled you to query tags and attributes with query syntax.
A very simple query good look like this:
// Load the xml from the specified path
var xml = XDocument.Load(#"LocationOfXml");
// Query the first element with a "MyXmlTag" as name
var someAttribute = xml.Descendants().FirstOrDefault(x => x.Name == "MyXmlTag");
The query language is far richer than this simple query. Read up and im sure you'll be able to get it working asap.

Appending/Listing LINQ to XML data

I'm currently writing a function to save and read data to/from and XML document through
LINQ. Currently I can write the document just fine, but if I go to add data to an existing item, it simply adds a new item. My goal is to create an address book type system (yes I know there's 1000 out there, it's just a learning project for myself) and I've tried ini and basic text but it seems that XML is the best way to go short of using a local DB like sql. Currently I have:
XDocument doc = XDocument.Load(#"C:\TextXML.xml");
var data = new XElement("Entry",
new XElement("Name", textBox1.Text),
new XElement("Address", richTextBox2.Text),
new XElement("Comments", richTextBox1.Text));
doc.Element("Contacts").Add(data);
doc.Save(#"C:\TextXML.xml");
I searched SO and can't seem to find how to append/replace.
Now this saves everything properly, even when I add to the document, but if I want to update an entry I'm not sure how to without creating a new "Entry" nor am have I gotten the knack of removing one. (I'm somewhat new to C# still and self-taught so pardon anything obvious I've overlooked.)
My second issues revolves around loading the information into textboxes.
I'm able to load a list of Entry names into a listbox, but when I go to open the information from that entry I'm not sure how to properly get the nested info.
With the example above I'd need something similar to the following:
XDocument doc = XDocument.Load(#"C:\TextXML.xml");
boxName.Text = The name from the SelectedItem of the list box.
boxAddress.Text = The address child of the element named above etc.
Each method I've tried I wind up with a null reference exception, which tells me I'm not pointing to the right thing, but I'm not sure how to get to those things properly.
I've also tried creating a string and var of the SelectedItem from the list box to help with the naming, and using ToString methods, but still can't figure it out.
For replacing values, there are several functions you can use in XElement:
Value (property with a public setter)
SetValue()
SetElementValue()
SetAttributeValue()
ReplaceWith()
ReplaceNodes()
For example, if you wanted to replace the value in Name:
data.Element("Name").SetValue("NewValue");
or
data.Element("Name").Value = "NewValue";
For loading, once you have the XElement node you desire, then it's as simple as doing
xelement.Value
Or if it's an attribute:
xelement.Attribute("AttributeName").Value
Using your code as an example:
boxName.Text = doc.Element("Entry").Element("Name").Value;
Edit to address comment:
If I'm reading your comment right, you're wanting to extract the Name/Address/etc. data from all the nodes within the Contacts main node?
If so, then you would probably want something like this:
boxName.Text = string.Join(",", doc.Elements("Entry").Select(x => x.Element("Name").Value));
This will give you a single string that has all the names in all Entries separated by a comma. Just change "Name" to "Address" to do the same for addresses.
I'd suggest doing a search for Linq to XML for finding more information about how to use this parsing.

Validating and Extracting XML record by record into Database

Here's the deal. I have an XML document with a lot of records. Something like this:
print("<?xml version="1.0" encoding="utf-8" ?>
<Orders>
<Order>
<Phone>1254</Phone>
<City>City1</City>
<State>State</State>
</Order>
<Order>
<Phone>98764321</Phone>
<City>City2</City>
<State>State2</State>
</Order>
</Orders>");
There's also an XSD schema file. I would like to extract data from this file and insert these records into a database table. First of course I would like to validate each order record. For example if there are 5 orders in the file and 2 of them fail validation I would like to insert the 3 that passed validation into the db and left the other 2. There can be thousands of records in one xml file. What would be the best approach here. And how would the validation go for this since I need to discard the failed records and only use the ones that passed validation. At the moment I'm using XmlReaderSettings to validate the XML document records. Should I extract these records into another XML file or a Dataset or a custom object before I insert into a DB. I'm using .Net 3.5. Any code or link is welcome.
If the data maps fairly cleanly to an object model, you could try using xsd.exe to generate some classes from the .xsd, and process the classes into your DAL of choice. The problem is that if the volume is high (you mention thousands of records), you will most likely have a lot of round-trips.
Another option might be to pass the data "as is" through to the database and use SQL/XML to process the data in TSQL - presumably as a stored procedure that accepts a parameter of type xml (SQL Server 2005 etc).
I agree with idea that you should use an XmlReader, but I thought I'd try something a little different.
Basically, I am first validating the whole XDocument, then if there are errors, I enumerate through the orders and bin them as needed. It's not pretty, but maybe it'll give you some ideas.
XDocument doc = XDocument.Load("sample.xml");
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", "sample.xsd");
bool errors = false;
doc.Validate(schemas, (sender, e) =>
{
errors = true;
});
List<XElement> good = new List<XElement>();
List<XElement> bad = new List<XElement>();
var orders = doc.Descendants("Order");
if (errors)
{
foreach (var order in orders)
{
errors = false;
order.Validate(order.GetSchemaInfo().SchemaElement, schemas, (sender, e) =>
{
errors = true;
});
if (errors)
bad.Add(order);
else
good.Add(order);
}
}
else
{
good = orders.ToList();
}
Instead of the lambda expressions, you could use a common function, but I just threw this together. Also, you could build two XDocuments instead of shoving the order elements into a list. I'm sure there are a ton of other problems here too, but maybe this will spark something.
You have a couple of options:
XmlDataDocument or XmlDocument. The downside to this approach is that the data will be cached in memory, which is bad if you have a lot of it. On the other hand, you get good in-memory querying facilities with DataSet. XmlDocument requires that you use XPath queries to work on the data, whereas XmlDataDocument gives you an experience more like the DataSet functionality.
XmlReader. This is a good, fast approach because the data isn't cached; you read it in a bit at a time as a stream. You move from one element to the next, and query information about that element in your application to decide what to do with it. This does mean that you maintain in your application's memory the tree level that you're at, but with a simple XML file structure like yours this should be very simple.
I recommend option 2 in your case. It should scale well in terms of memory usage, and should provide the simplest implementation for processing a file.
A lot of that depends on what "validation" means in your scenario. I assume, since you're using an .xsd, you are already validating that the data is syntactically correct.
So, validation probably means you'll be calling other services or procedures to determine if an order is valid?
You might want to look at Sql Server Integration Services. The XML Task in SSIS lets you do things like XPath queries, merging, likely anything and everything you'd need to do with that document. You could also use that do to all of your upfront validation with schema file too.
Marc's option of passing that data to a stored procedure might work in this scenario too, but SSIS (or, even DTS but you're going to give up too much related to XML to make it as nice of an option) will let you visually orchestrate all of this work. Plus, it'll make it easier for these things to run out of process so you should end up with a much more scalable solution.
By validation I mean validating each node. The nodes that have at least one error need to be inserted into a new xml document. Basically at the end I should have 2 xml documents. One containing the successful nodes and the other containing the failure nodes. Any way I can accomplish that? I'm using LINQ.

Categories

Resources