XmlDocument in place transform with XSL - c#

I'm sorry if this is an obvious question, but I'm getting abit frustrated trying to find an answer.
Can I perform an XSL transform on a loaded XmlDocument in place? That is, without having to create a writer to the document?
I ask because I have an XmlDocument binding inside a WPF app that I want to sort. The sorts can get a little complicated so XSL seemed a good fit. Here's the code that I'm stuck at:
XmlDataProvider xmlDP = (XmlDataProvider)this.Resources["ItemDB"];
string xsltPath = System.Configuration.ConfigurationManager.AppSettings["XSLDirextory"];
string path = xsltPath + "SortItemName.xslt";
if (System.IO.File.Exists(path))
{
XslCompiledTransform compTrans = new XslCompiledTransform();
compTrans.Load(path);
//compTrans.Transform(xmlDP.Document, new XsltArgumentList(), xmlDP.Document.XmlResolver);
}
After loading the transform, I'd like to just be able to compTrans(xmlDP.Document); or something that has the same effect. (to be clear, xmlDP.Document is an XmlDocument ) so that the XmlDocument has the result of the transform.
What's the best way to accomplish this?

The closest you can do is create a new XmlDocument with e.g.
XmlDocument result = new XmlDocument();
using (XmlWriter xw = result.CreateNavigator().AppendChild())
{
compTrans.Transform(xmlDP.Document, null, xw);
xw.Close();
}
and then assign that to your property:
xmlDP.Document = result;
Of course that requires that xmlDP.Document can be set.

XSLT always creates a new document to hold the transformation result, it never modifies the input document.

Related

How to resolve IOException "file used by another process" while saving XmlDocument?

When I'm trying to save the XML Document I edited the IOException "file used by another process" occured when I try to save that document.
Any ideas how to solve this?
Note: This method is called everytime a new element in the XmlDocument should be written.
public void saveRectangleAsXMLFragment()
{
XmlDocument doc = new XmlDocument();
doc.Load("test.xml");
XmlDocumentFragment xmlDocFrag = doc.CreateDocumentFragment();
String input = generateXMLInput();
xmlDocFrag.InnerXml = input;
XmlElement mapElement = doc.DocumentElement;
mapElement.AppendChild(xmlDocFrag);
input = null;
mapElement = null;
xmlDocFrag = null;
doc.Save("test.xml");
}
Its probably one of your other methods, or other part of the code which opened the file and didnt calose it well. Try to search for this kind of problem.
try this if your's application is only access that .xml file
1. Create a Object globally
object lockData = new object();
2.Use than object to lock statement where you save and load xml
lock(lockData )
{
doc.Load("test.xml");
}
lock(lockData )
{
doc.Save("test.xml");
}
From Jon Skeet's related answer (see https://stackoverflow.com/a/8354736/4151626)
There seems to be a bug in XmlDocument.Save()'s treatment of the file stream, where it becomes pinned and is neither Closed() nor Disposed(). By taking direct control of the creation and disposition of the stream outside of the XmlDocument.Save() I was able to get around this halting error.
//e.g.
XmlWriter xw = new XmlWriter.Create("test.xml");
doc.Save(xw);
xw.Close();
xw.Dispose();

Generate XML from C# Code

I have to generate specific XML data from code.
The XML needs to look like this
<this:declarationIdentifier xmlns:this="demo.org.uk/demo/DeclarationGbIdentifier"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="demo.org.uk/demo/DeclarationGbIdentifier DeclarationGbIdentifier.xsd"
xmlns:nsIdentity="demo.org.uk/demo/DeclarationGbIdentityType">
<this:declarationIdentity>
<nsIdentity:declarationUcr>Hello World</nsIdentity:declarationUcr>
</this:declarationIdentity>
</this:declarationIdentifier>
I have dabbled with XmlSerializer and XDocument but cant get the output to match this exactly
Please help.
I believe this will produce your desired output. There possibly is a simpler way this is just off the cuff to get you started. With the prefixes that you are requiring I would look up XmlDocument and adding namespaces to it to have a better understanding of what the code below is doing. Also what I would do is attempt to acquire the XSD schema file and use the XSD.exe to build a .cs file and then you can move forward with the XmlSerializer. If you move forward with the code below i highly suggest moving off your namespaceuri's into some soft of settings file so you can easily modify them in the event they change.
XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement("this", "declarationIdentifier", "demo.org.uk/demo/DeclarationGbIdentifier");
root.SetAttribute("xmlns:this", "demo.org.uk/demo/DeclarationGbIdentifier");
root.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
//Just setting an Attribute of xsi:schemaLocation it would always drop the xsi prefix in the xml so this is different to accomodate that
XmlAttribute schemaAtt = doc.CreateAttribute("xsi", "schemaLocation", "http://www.w3.org/2001/XMLSchema-instance");
schemaAtt.Value = "demo.org.uk/demo/DeclarationGbIdentifier DeclarationGbIdentifier.xsd";
root.Attributes.Append(schemaAtt);
root.SetAttribute("xmlns:nsIdentity", "demo.org.uk/demo/DeclarationGbIdentityType");
doc.AppendChild(root);
XmlElement declarationIdentity = doc.CreateElement("this", "declarationIdentity", "demo.org.uk/demo/DeclarationGbIdentifier");
XmlElement declarationUcr = doc.CreateElement("nsIdentity","declarationUcr","demo.org.uk/demo/DeclarationGbIdentityType");
declarationUcr.InnerText = "Hello World";
declarationIdentity.AppendChild(declarationUcr);
doc.DocumentElement.AppendChild(declarationIdentity);
To output this as a string or dump it off to a file you can use the following operations, I output to a file as well as output to the console in my test app.
using (var stringWriter = new StringWriter())
using (StreamWriter writer = new StreamWriter(#"C:\<Path to File>\testing.xml"))
using (var xmlTextWriter = XmlWriter.Create(stringWriter))
{
doc.WriteTo(xmlTextWriter);
xmlTextWriter.Flush();
writer.Write(stringWriter.GetStringBuilder().ToString());
Console.WriteLine(stringWriter.GetStringBuilder().ToString());
}

XSLT, XML. HTML helper not working

So I retrieve an XML and XSLT as strings from the DB then used my custom HTML helper called RenderXml to render. The problem is that it is not rendering properly. In my HTML helper is where I do the transformation
public static HtmlString RenderXml(this HtmlHelper helper, string theXml, string theXslt)
{
XDocument xmlTree = XDocument.Parse(xmlPath);
XDocument newTree = new XDocument();
using (XmlWriter writer = newTree.CreateWriter())
{
// Load the style sheet.
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(XmlReader.Create(new StringReader(xsltPath)));
// Execute the transform and output the results to a writer.
xslt.Transform(xmlTree.CreateReader(), writer);
return new HtmlString(newTree.ToString());
}
}
in my CSHTML I do it like this
<div id="results">#Html.RenderXml(Model.theXmlFile, Model.theXSLFile,)</div>
When I try to return new HtmlString(newTree.ToString()); I get a blank, and when I try to return new HtmlString(writer.ToString()); I get this System.Xml.XmlWellFormedWriter on the page. Do anybody know what I am doing wrong? I got my code from the example here. I have also looked into this one and it works great except I do not use a URI, and when I try to modify it to use XDocument complains about missing parameters, so I stayed away from it. Any ideas why he transformation is not working?
Try moving the line return new HtmlString(newTree.ToString()); outside of the using block:
using (XmlWriter writer = newTree.CreateWriter())
{
// Load the style sheet.
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(XmlReader.Create(new StringReader(xsltPath)));
// Execute the transform and output the results to a writer.
xslt.Transform(xmlTree.CreateReader(), writer);
}
return new HtmlString(newTree.ToString());

Creating an XML with multiple root elements

I'm trying to create an XML with multiple root elements. I can't change that because that is the way I'm supposed to send the XML to the server. This is the error I get when I try to run the code:
System.InvalidOperationException: This operation would create an incorrectly structured document.
Is there a way to overwrite this error and have it so that it ignores this?
Alright so let me explain this better:
Here is what I have
XmlDocument doc = new XmlDocument();
doc.LoadXml(_application_data);
Now that creates the XML document and I can add a fake root element to it so that it works. However, I need to get rid of that and convert it into a DocumentElement object.
How would I go about doing that?
Specify Fragment when creating XmlWriter as shown here
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.ConformanceLevel = ConformanceLevel.Fragment;
settings.CloseOutput = false;
// Create the XmlWriter object and write some content.
MemoryStream strm = new MemoryStream();
using (XmlWriter writer = XmlWriter.Create(strm, settings))
{
writer.WriteElementString("orderID", "1-456-ab");
writer.WriteElementString("orderID", "2-36-00a");
writer.Flush();
}
If it has multiple root elements, it's not XML. If it resembles XML in other ways, you could place everything under a root element, then when you send the string to the server, you just combine the serialized child elements of this root element, or as #Austin points out, use an inner XML method if available.
just create an XML with single root then get it's content as XML text.
you are talking about XML fragment anyways, since good xml has only one root.
this is sample to help you started:
var xml = new XmlDocument();
var root = xml.CreateElement("root");
root.AppendChild(xml.CreateElement("a"));
root.AppendChild(xml.CreateElement("b"));
Console.WriteLine(root.InnerXml); // outputs "<a /><b />"

Trying to parse xml, but xmldocument.loadxml() is trying to download?

I have a string input that i do not know whether or not is valid xml.
I think the simplest aprroach is to wrap
new XmlDocument().LoadXml(strINPUT);
In a try/catch.
The problem im facing is, sometimes strINPUT is an html file, if the header of this file contains
<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">
<html xml:lang=""en-GB"" xmlns=""http://www.w3.org/1999/xhtml"" lang=""en-GB"">
...like many do, it actually tries to make a connection to the w3.org url, which i really dont want it doing.
Anyone know if its possible to just parse the string without trying to be clever and checking external urls? Failing that is there an alternative to xmldocument?
Try the following:
XmlDocument doc = new XmlDocument();
using (var reader = XmlReader.Create(new StringReader(xml), new XmlReaderSettings() {
ProhibitDtd = true,
ValidationType = ValidationType.None
})) {
doc.Load(reader);
}
The code creates a reader that turns off DTD processing and validation. Checking for wellformedness will still apply.
Alternatively you can use XDocument.Parse if you can switch to using XDocument instead of XmlDocument.
I am not sure about the reason behind the problem but Have you tried XDocument and XElement classes in System.Xml.Linq
XDocument document = XDocument.Load(strINPUT , LoadOptions.None);
XElement element = XElement.Load(strINPUT );
EDIT: for xml as string try following
XDocument document = XDocument.Parse(strINPUT , LoadOptions.None );
Use XmlDocument's load method to load the xml document, use XmlNodeList to get at the elements, then retrieve the data ...
try the following:
XmlDocument xmlDoc = new XmlDocument();
//use the load method to load the XML document from the specified stream.
xmlDoc.Load("myXMLDoc.xml");
//Use the method GetElementsByTagName() to get elements that match the specified name.
XmlNodeList item = xDoc.GetElementsByTagName("item");
XmlNodeList url = xDoc.GetElementsByTagName("url");
Console.WriteLine("The item is: " + item[0].InnerText));
add a try/catch block around the above code and see what you catch, modify your code to address that situation.

Categories

Resources