XslCompiledTransform cant transform with XmlTestReader created from string - c#

I have a problem with XslCompiledTransform class.
If I tried to run this code:
string pathToXsltFile, pathToInputFile, pathToOutputFile;
XsltSettings xsltSettings = new XsltSettings(true, true);
XslCompiledTransform myXslTransform = new XslCompiledTransform();
XmlTextReader reader = new XmlTextReader(pathToFile);
myXslTransform.Load(reader, xsltSettings, new XmlUrlResolver());
myXslTransform.Transform(pathToInputFile, pathToOutputFile);
It works fine.
But if I want to create XmlTextReader from a string (text):
MemoryStream mStrm = new System.IO.MemoryStream(Encoding.UTF8.GetBytes(text));
XmlTextReader xmlReader = new XmlTextReader(mStrm);
mStrm.Position = 0;
And try to run:
myXslTransform.Load(xmlReader, xsltSettings, new XmlUrlResolver());
myXslTransform.Transform(pathToInputFile, pathToOutputFile);
I get a Exception:
"this operation is not supported for a relative uri"
For some reasons I don't want to create temporaty file and create XmlTextReader from path to this file.
Edit:
Full exception message:
"An error occurred while loading document ''.
See InnerException for a complete description of the error."
InnerException.Message:
"This operation is not supported for a relative URI."
Stack trace:
at System.Xml.Xsl.Runtime.XmlQueryContext.GetDataSource(String uriRelative, String uriBase)
at <xsl:template match=\"gmgml:FeatureCollection\">(XmlQueryRuntime {urn:schemas-microsoft-com:xslt-debug}runtime, XPathNavigator {urn:schemas-microsoft-com:xslt-debug}current)
at <xsl:apply-templates>(XmlQueryRuntime {urn:schemas-microsoft-com:xslt-debug}runtime, XPathNavigator )
at Root(XmlQueryRuntime {urn:schemas-microsoft-com:xslt-debug}runtime)
at Execute(XmlQueryRuntime {urn:schemas-microsoft-com:xslt-debug}runtime)
at System.Xml.Xsl.XmlILCommand.Execute(Object defaultDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlSequenceWriter results)
at System.Xml.Xsl.XmlILCommand.Execute(Object defaultDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter writer, Boolean closeWriter)
at System.Xml.Xsl.XmlILCommand.Execute(XmlReader contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, Stream results)
at System.Xml.Xsl.XslCompiledTransform.Transform(String inputUri, String resultsFile)
at MyNamespace.ApplyXslTransformation1(String input, String output, String xsltFileName)
the statement causing the exception:
myXslTransform.Transform(pathToInputFile, pathToOutputFile);
About the document function I will have to ask tommorrow. I've get the xslt file from the other person.
When I've created the XmlTextReader file from the path to the xslt file everytning was fine. I've also try to use:
myXslTransform.Load(pathToXsltFile, xsltSettings, new XmlUrlResolver());
myXslTransform.Transform(pathToInputFile, pathToOutputFile);
And it was also fine.
Now i get the encrypted xslt. I've decrypt it and I want to create XmlTextReader from the decrypted string. Besause of the security reason i don't wont to create temporaty xslt decrypted file.

I think we need to see the XSLT and any calls to the document function it does. In general you need to be aware that the document function has a second argument that can serve as a base URI to resolve URIs resulting from the first argument. Without the second argument being passed in as in e.g. <xsl:value-of select="document('foo.xml')"/> the stylesheet code itself provides the base URI. If you load the stylesheet code from a string that mechanism might not resolve URIs the same way as it happens with a stylesheet loaded from the file system or a HTTP URI. The solution to that problem depends on the location of the resource you want to load and how that relates to the main input file. If you want to load foo.xml from the same location as the main input document then doing document('foo.xml', /) instead of document('foo.xml') should work.

I think this is caused by your manual setting of the memory stream's position to 0; you're confusing the XmlTextReader.
I tried the above and it works fine for me when I comment that line out.
Is there a particular reason you are setting it to 0?

Assuming this question is about using XslCompiledTransform in a .Net Core application, I found the answer to "This operation is not supported for a relative URI." at the site https://github.com/dotnet/corefx/issues/31390
The relevant answer (by vcsjones commented on Jul 26, 2018) is:
"I believe you are running in to a known compatibility change. .NET Core does not allow resolving external URIs for XML by default and is documented here.
As the documentation says, the old behavior can be restored, if you so choose, by putting
AppContext.SetSwitch("Switch.System.Xml.AllowDefaultResolver", true);
In your application. Try placing that at the top of your example program."
When I added
AppContext.SetSwitch("Switch.System.Xml.AllowDefaultResolver", true);
as the top line of
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
in startup, the error "This operation is not supported for a relative URI" went away. At that moment, a new error occurred calling Load with a XmlReader relating to finding the other files referenced by the XSL file. When I then instead passed the file path to the xsl in Load, it all worked as expected.
var resolver = new XmlUrlResolver {Credentials = CredentialCache.DefaultCredentials};
var transform = new XslCompiledTransform();
transform.Load(XslPath, new XsltSettings(true, true), resolver);
var settings = new XmlWriterSettings {OmitXmlDeclaration = true};
using (var results = new StringWriter())
using(var writer = XmlWriter.Create(results, settings))
{
using (var reader = XmlReader.Create(new StringReader(document)))
{
transform.Transform(reader, writer);
}
return results.ToString();
}
I add this in hope helps someone else trying to debug why XslCompiledTransform thows "This operation is not supported for a relative URI." in .net core.

Related

DTD security error when i apply an XSLT stylesheet

I got an error that i can't solve for the moment
The code :
var myXslTrans = new XslCompiledTransform();
myXslTrans.Load(stylesheet);
myXslTrans.Transform(sourceFile , outputFile);
The error :
For safety reasons, DTC prohibited in this XML document To enable DTD
processing , set on the Parse DtdProcessing property XmlReaderSettings
and pass parameters to the XmlReader.Create method
I have tried with the XmlReaderSettings (DtdProcessing, DtdProcessing.Parse) but i didn't find the answer
If the stylesheet document uses a DTD (e.g. has <!DOCTYPE xsl:stylesheet ...>) then load it with
using (XmlReader xr = XmlReader.Create(stylesheet, new XmlReaderSettings() { DtdProcessing = DtdProcessing.Parse }))
{
myXslTrans.Load(xr);
}
If the sourceFile uses a DTD then load it with such an XmlReader passed as the first argument to the Transform method, you might then need a different overload of that method for the second and third argument.

XDocument prevent invalid characters

I am using XDocument to keep a sort of database. This database consists of registered chatterbots, and I simply have many "bot" nodes with attributes such as "username", "owner", and such. However, occasionally some smart guy decides to make a bot with a very strange character as one of the properties. This makes the XDocument class series throw an exception whenever that node is read, a very large problem because the database fails to save completely as it stops writing to the file as soon as it hits the invalid character.
My question is this- Is there a simple method that is something like XSomething.IsValidString(string s), so I can just omit the offending data? My database is not the official one, just a personal use, so it is not imperative that I include the bad data.
Some code that I am using (the variable file is the XDocument):
To save:
file.Save(Path.Combine(Environment.CurrentDirectory, "bots.xml"));
To load (after checking if File.Exists() etc etc):
file = XDocument.Load(Path.Combine(Environment.CurrentDirectory, "bots.xml"));
To add to the database (variables are all strings):
file.Root.Add(new XElement("bot",
new XAttribute("username", botusername),
new XAttribute("type", type),
new XAttribute("botversion", botversion),
new XAttribute("bdsversion", bdsversion),
new XAttribute("owner", owner),
new XAttribute("trigger", trigger)));
Pardon my lack of proper XML techniques, I'm just starting. What I'm asking is if there is a XSomething.IsValidString(string s) method, not how terrible my XML is.
Ok, I just got the exception again, here is the exact message and stack trace.
System.ArgumentException: '', hexadecimal value 0x07, is an invalid character.
at System.Xml.XmlUtf8RawTextWriter.InvalidXmlChar(Int32 ch, Byte* pDst, Boolean entitize)
at System.Xml.XmlUtf8RawTextWriter.WriteAttributeTextBlock(Char* pSrc, Char* pSrcEnd)
at System.Xml.XmlUtf8RawTextWriter.WriteString(String text)
at System.Xml.XmlUtf8RawTextWriterIndent.WriteString(String text)
at System.Xml.XmlWellFormedWriter.WriteString(String text)
at System.Xml.XmlWriter.WriteAttributeString(String prefix, String localName, String ns, String value)
at System.Xml.Linq.ElementWriter.WriteStartElement(XElement e)
at System.Xml.Linq.ElementWriter.WriteElement(XElement e)
at System.Xml.Linq.XElement.WriteTo(XmlWriter writer)
at System.Xml.Linq.XContainer.WriteContentTo(XmlWriter writer)
at System.Xml.Linq.XDocument.WriteTo(XmlWriter writer)
at System.Xml.Linq.XDocument.Save(String fileName, SaveOptions options)
at System.Xml.Linq.XDocument.Save(String fileName)
at /* my code stack trace omitted */
Try changing the file.Save line for the following code:
XmlWriterSettings settings = new XmlWriterSettings();
settings.CheckCharacters = false;
XmlWriter writer = XmlWriter.Create(Path.Combine(Environment.CurrentDirectory, "bots.xml"), settings);
file.Save(writer);
source: http://sartorialsolutions.wordpress.com/page/2/
First can you check whether your XML file is saved with proper encoding? I normally save xml file as UTF8 and You can declare encoding in your xml header
<?xml version="1.0" encoding="UTF-8"?>
Of course the body of your xml must conforming xml standard. Here is a good article about it
http://weblogs.sqlteam.com/mladenp/archive/2008/10/21/Different-ways-how-to-escape-an-XML-string-in-C.aspx
From .NET 4, you can use XmlConvert.VerifyXmlChars(string content). This will throw an exception if the string passed is not accepted.

How to transform XMLDocument using XSLT in C# 2.0

I am using C# 2.0 and I have got below code:
XmlDocument doc = new XmlDocument();
doc.LoadXml(GetListOfPagesInStructureGroup(m_Page.Id));
In above I am loading my XMLDocument with method which returns as string, now after some processing on above xmldocument I want to apply XSLT on the above XMLDocument to render my desired result according to XSLT and finally my function will return whole rendered XML as string
Please suggest!!
Please suggest on below solution:
XslCompiledTransform xslTransform = new XslCompiledTransform();
StringWriter writer = new StringWriter();
xslTransform.Load("xslt/RenderDestinationTabXML.xslt");
xslTransform.Transform(doc.CreateNavigator(),null, writer);
return writer.ToString();
Thanks!!
Try the XslCompiledTransform class.
There are lots of examples on the web of transforming an XML file to a different format using an XSLT file, like the following:
XslTransform myXslTransform = new XslTransform();
XsltSettings myXsltSettings = new XsltSettings();
myXsltSettings.EnableDocumentFunction = true;
myXslTransform.Load("transform.xsl");
myXslTransform.Transform("input.xml", "output.xml");
However this is only a partial answer, I would like to be able to get the XML input data from a web form and use that as the input data instead of an '.xml' file, but have not found any concrete examples, also using Visual Studio I can see the different constructors and methods that are available and I am not seeing one that accepts xml data in a string format, so it would be very helpful if someone could provide an example of that.
Re " I want my same XMlDocument updated " - it doesn't work like that; the output is separate to the input. If that is important, just use a StringWriter or MemoryStream as the destination, then reload the XmlDocument from the generated output.
Consider in particular: the output from an xslt transformation does not have to be xml, and also: the xslt is most likely using the node tree during the operation; changing the structure in-place would make that very hard.

xml parsing problem with c# linq to xml - Reference to undeclared entity

tryin to parse an xml file gives me the following error
Reference to undeclared entity 'eacute'
after I created a dtd file with all the entities that I found here http://www.w3.org/TR/xhtml1/dtds.html and I loaded it as follows
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
string s = System.IO.File.ReadAllText(#"..\xhtml-lat1.ent");
XmlParserContext con = new XmlParserContext(null, null, "iti", null, null, s, "", "", XmlSpace.None);
XmlReader reader = XmlReader.Create(stream, settings, con);
the loading an xdocument
XDocument doc = XDocument.Load(reader);
give me the following exception '=' is an unexpected token. The expected token is ';'.
any suggestions please
Generally, this error happens when the xml document is not well-formed.
One tip to find the error, open your xml document in Internet Explorer. If the xml document is not well-formed, Internet Explorer will not be able to load the entire document and will tell you where the error is located.
If I recall correctly, the only place a semicolon matters in XML is in an entity encoding. I would check for an incomplete entity (maybe &eacute) or a special character in the document that should be encoded.

Prevent DTD download when parsing XML

When using XmlDocument.Load , I am finding that if the document refers to a DTD, a connection is made to the provided URI. Is there any way to prevent this from happening?
After some more digging, maybe you should set the XmlResolver property of the XmlReaderSettings object to null.
'The XmlResolver is used to locate and
open an XML instance document, or to
locate and open any external resources
referenced by the XML instance
document. This can include entities,
DTD, or schemas.'
So the code would look like this:
XmlReaderSettings settings = new XmlReaderSettings();
settings.XmlResolver = null;
settings.DtdProcessing = DtdProcessing.Parse;
XmlDocument doc = new XmlDocument();
using (StringReader sr = new StringReader(xml))
using (XmlReader reader = XmlReader.Create(sr, settings))
{
doc.Load(reader);
}
The document being loaded HAS a DTD.
With:
settings.ProhibitDtd = true;
I see the following exception:
Service cannot be started. System.Xml.XmlException: For security reasons DTD is prohibited in this XML document. To enable DTD processing set the ProhibitDtd property on XmlReaderSettings to false and pass the settings into XmlReader.Create method.
So, it looks like ProhibitDtd MUST be set to true in this instance.
It looked like ValidationType would do the trick, but with:
settings.ValidationType = ValidationType.None;
I'm still seeing a connection to the DTD uri.
This is actually a flaw in the XML specifications. The W3C is bemoaning that people all hit their servers like mad to load schemas billions of times. Unfortunately just about no standard XML library gets this right, they all hit the servers over and over again.
The problem with DTDs is particularly serious, because DTDs may include general entity declarations (for things like & -> &) which the XML file may actually rely upon. So if your parser chooses to forgo loading the DTD, and the XML makes use of general entity references, parsing may actually fail.
The only solution to this problem would be a transparent caching entity resolver, which would put the downloaded files into some archive in the library search path, so that this archive would be dynamically created and almost automatically bundled with any software distributions made. But even in the Java world there is not one decent such EntityResolver floating about, certainly not built-in to anything from apache foundation.
Try something like this:
XmlDocument doc = new XmlDocument();
using (StringReader sr = new StringReader(xml))
using (XmlReader reader = XmlReader.Create(sr, new XmlReaderSettings()))
{
doc.Load(reader);
}
The thing to note here is that XmlReaderSettings has the ProhibitDtd property set to true by default.
Use an XMLReader to load the document and set the ValidationType property of the reader settings to None.

Categories

Resources