Using SAXON 9.5 (nuget) with Schematron - c#

I am running this code:
string path = AppDomain.CurrentDomain.BaseDirectory;
// Uri schemaUri = new Uri(#"file:\\" + path + #"\sch\patient.sch");
Uri totransformEE = new Uri(#"file:\\" + path + #"\po\po-schema.sch");
Uri transformER = new Uri(#"file:\\" + path + #"\xsl\conformance1-5.xsl");
///////////////////////////////
// Crate Schemtron xslt to be applied
///////////////////////////////
// Create a Processor instance.
Processor processor = new Processor();
// Load the source document
XdmNode input = processor.NewDocumentBuilder().Build(totransformEE);
// Create a transformer for the stylesheet.
XsltTransformer transformer = processor.NewXsltCompiler().Compile(transformER).Load();
// Set the root node of the source document to be the initial context node
transformer.InitialContextNode = input;
// Create a serializer
Serializer serializer = new Serializer();
MemoryStream st = new MemoryStream();
serializer.SetOutputStream(st);
// Transform the source XML to System.out.
transformer.Run(serializer);
st.Position = 0;
System.IO.StreamReader rd = new System.IO.StreamReader(st);
string xsltSchematronStylesheet = rd.ReadToEnd();
System.Diagnostics.Debug.WriteLine(xsltSchematronStylesheet);
// Load the source document
Uri transformEE2 = new Uri(#"file:\\" + path + #"\po\po-bad.xml");
var documentbuilder2 = processor.NewDocumentBuilder();
XdmNode input2 = documentbuilder2.Build(transformEE2);
////// Create a transformer for the stylesheet.
StringReader sr2 = new StringReader(xsltSchematronStylesheet);
XsltTransformer transformer2 = processor.NewXsltCompiler().Compile(sr2).Load();
// Set the root node of the source document to be the initial context node
transformer2.InitialContextNode = input2;
// Create a serializer
Serializer serializer2 = new Serializer();
MemoryStream st2 = new MemoryStream();
serializer.SetOutputStream(st2);
transformer2.MessageListener = new MyMessageListener();
// Transform the source XML to System.out.
transformer2.Run(serializer2);
st2.Position = 0;
System.IO.StreamReader rd2 = new System.IO.StreamReader(st2);
string xsltSchematronResult = rd2.ReadToEnd();
System.Diagnostics.Debug.WriteLine(xsltSchematronResult);
I get what appears to be an XSLT file when examining xsltSchematronStylesheet. However the stream at the end st2 has 0 length. Also, MyMessageListener.Message receives no calls (I used a break point).
I am not sure if I have bad code, bad sample files, etc.
I believe my sample files are correct, but maybe I have bad ones or am missing some.
Does anyone know why no data is returned to the stream st2. If not can you direct me to a good simple sample that has all the files and works?

My real underlying problem was finding simple complete sample code to do Schematron in .Net. So for the next guy here is the sample I was looking for. I have tried to make this as complete as possible. If I missed something, leave a comment.
Create a unit test project
Run the Nuget Command
Download the Schematron files
Use the included classes and sch, xml files.
Run the test program
Nuget Saxon Commandline:
Install-Package Saxon-HE
Download Up to date Schematron Files
http://www.schematron.com/tmp/iso-schematron-xslt2.zip
UnitTest:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
namespace SOAPonFHIR.Test
{
[TestClass]
public class Schematron
{
[TestMethod]
public void XSLT_SAXON_Simple_Schematron2()
{
///////////////////////////////
// Transform original Schemtron
///////////////////////////////
string path = AppDomain.CurrentDomain.BaseDirectory;
Uri schematron = new Uri(#"file:\\" + path + #"\simple\input.sch");
Uri schematronxsl = new Uri(#"file:\\" + path + #"\xsl_2.0\iso_svrl_for_xslt2.xsl");
Stream schematrontransform = new Test.XSLTransform().Transform(schematron, schematronxsl);
///////////////////////////////
// Apply Schemtron xslt
///////////////////////////////
FileStream xmlstream = new FileStream(path + #"\simple\input.xml", FileMode.Open, FileAccess.Read, FileShare.Read);
Stream results = new Test.XSLTransform().Transform(xmlstream, schematrontransform);
System.Diagnostics.Debug.WriteLine("RESULTS");
results.Position = 0;
System.IO.StreamReader rd2 = new System.IO.StreamReader(results);
string xsltSchematronResult = rd2.ReadToEnd();
System.Diagnostics.Debug.WriteLine(xsltSchematronResult);
}
}
}
Transform Class:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using Saxon.Api;
using System.IO;
using System.Xml.Schema;
using System.Collections.Generic;
namespace SOAPonFHIR.Test
{
public class XSLTransform
{
public Stream Transform(Uri xmluri, Uri xsluri)
{
// Create a Processor instance.
Processor processor = new Processor();
// Load the source document
XdmNode input = processor.NewDocumentBuilder().Build(xmluri);
// Create a transformer for the stylesheet.
var compiler = processor.NewXsltCompiler();
compiler.ErrorList = new System.Collections.Generic.List<Exception>();
XsltTransformer transformer = compiler.Compile(xsluri).Load();
if (compiler.ErrorList.Count != 0)
throw new Exception("Exception loading xsl!");
// Set the root node of the source document to be the initial context node
transformer.InitialContextNode = input;
// Create a serializer
Serializer serializer = new Serializer();
MemoryStream results = new MemoryStream();
serializer.SetOutputStream(results);
// Transform the source XML to System.out.
transformer.Run(serializer);
//get the string
results.Position = 0;
return results;
}
public System.IO.Stream Transform(System.IO.Stream xmlstream, System.IO.Stream xslstream)
{
// Create a Processor instance.
Processor processor = new Processor();
// Load the source document
var documentbuilder = processor.NewDocumentBuilder();
documentbuilder.BaseUri = new Uri("file://c:/" );
XdmNode input = documentbuilder.Build(xmlstream);
// Create a transformer for the stylesheet.
var compiler = processor.NewXsltCompiler();
compiler.ErrorList = new System.Collections.Generic.List<Exception>();
compiler.XmlResolver = new XmlUrlResolver();
XsltTransformer transformer = compiler.Compile(xslstream).Load();
if (compiler.ErrorList.Count != 0)
throw new Exception("Exception loading xsl!");
// Set the root node of the source document to be the initial context node
transformer.InitialContextNode = input;
// Create a serializer
Serializer serializer = new Serializer();
MemoryStream results = new MemoryStream();
serializer.SetOutputStream(results);
// Transform the source XML to System.out.
transformer.Run(serializer);
//get the string
results.Position = 0;
return results;
}
}
}
Schematron File
<?xml version="1.0" encoding="utf-8"?>
<iso:schema
xmlns="http://purl.oclc.org/dsdl/schematron"
xmlns:iso="http://purl.oclc.org/dsdl/schematron"
xmlns:dp="http://www.dpawson.co.uk/ns#"
queryBinding='xslt2'
schemaVersion='ISO19757-3'>
<iso:title>Test ISO schematron file. Introduction mode</iso:title>
<iso:ns prefix='dp' uri='http://www.dpawson.co.uk/ns#'/>
<iso:pattern>
<iso:rule context="chapter">
<iso:assert
test="title">A chapter should have a title</iso:assert>
</iso:rule>
</iso:pattern>
</iso:schema>
XML File
<?xml version="1.0" encoding="utf-8" ?>
<doc>
<chapter id="c1">
<title>chapter title</title>
<para>Chapter content</para>
</chapter>
<chapter id="c2">
<title>chapter 2 title</title>
<para>Content</para>
</chapter>
<chapter id="c3">
<title>Title</title>
<para>Chapter 3 content</para>
</chapter>
</doc>
Results:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<svrl:schematron-output xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:saxon="http://saxon.sf.net/"
xmlns:schold="http://www.ascc.net/xml/schematron"
xmlns:iso="http://purl.oclc.org/dsdl/schematron"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:dp="http://www.dpawson.co.uk/ns#"
title="Test ISO schematron file. Introduction mode"
schemaVersion="ISO19757-3"><!--  
 
 
-->
<svrl:ns-prefix-in-attribute-values uri="http://www.dpawson.co.uk/ns#" prefix="dp"/>
<svrl:active-pattern document="file:///c:/"/>
<svrl:fired-rule context="chapter"/>
<svrl:fired-rule context="chapter"/>
<svrl:fired-rule context="chapter"/>
</svrl:schematron-output>

Resolution:
serializer.SetOutputStream(st2);
should be
serializer2.SetOutputStream(st2);

Related

.NET 6 XmlSerializer Pretty print

I've this sample .NET 6 program printing out a serialised object to XML:
using System.Text;
using System.Xml.Serialization;
var serializer = new XmlSerializer(typeof(Order));
var order = new Order
{
Address = new Address
{
FirstName = "Name"
}
};
await using var memoryStream = new MemoryStream();
var streamWriter = new StreamWriter(memoryStream, Encoding.UTF8);
serializer.Serialize(streamWriter, order);
var result = Encoding.UTF8.GetString(memoryStream.ToArray());
Console.WriteLine(result);
public class Order
{
public Address Address;
}
public class Address
{
public string FirstName;
}
This results in this output:
<?xml version="1.0" encoding="utf-8"?><Order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Address><FirstName>Name</FirstName></Address></Order>
In .NET 5 and .NET Core 3 similar code results in pretty printed XML like below. How can I format this XML in .NET6?
<?xml version="1.0" encoding="utf-8"?>
<Order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Address>
<FirstName>Name</FirstName>
</Address>
</Order>
To write indented xml you can use XmlTextWriter (instead of just StreamWriter) with Formatting set to Formatting.Indented:
await using var memoryStream = new MemoryStream();
XmlTextWriter streamWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
streamWriter.Formatting = Formatting.Indented;
serializer.Serialize(streamWriter, order);
var result = Encoding.UTF8.GetString(memoryStream.ToArray());
UPD
As #sveinungf wrote in the comment - using XmlWriter.Create is recommended approach, so the code can look like this (also note that Create method can accept StringBuilder or file name which can be more convenient in some scenarios):
await using var memoryStream = new MemoryStream();
var streamWriter = XmlWriter.Create(memoryStream, new()
{
Encoding = Encoding.UTF8,
Indent = true
});
serializer.Serialize(streamWriter, order);
var result = Encoding.UTF8.GetString(memoryStream.ToArray());

Change xslCompiledTransform output encoding while transformig

I am Converting my XML to XSLT by using xslCompiledTransform and when it transforms it changes the output result encoding which is UTF-16 (by default)
and when I try to change its or encoding it prompts the error that this property is read-only you can't change it!
I also try xmlWriter and xmlWriterSettings and memory Stream and other solutions but nothing works for me and for the reference I am adding code snippet
public static StringBuilder TransformXml(ProcessorConfigElement configSettings, StringBuilder xml, ILog logger)
{
//Perform transformation...
StringBuilder newXmlBuilder = new StringBuilder(xml.Length);
XslCompiledTransform requiredXslt = new XslCompiledTransform();
requiredXslt.Load(configSettings.XsltPath, XsltSettings.TrustedXslt, new XmlUrlResolver());
// I tried this trick also but all in vain
// Encoding wind1252 = Encoding.GetEncoding(1252);
// XmlWriterSettings xmlSettings = new XmlWriterSettings();
// xmlSettings.Encoding = wind1252;
// xmlSettings.ConformanceLevel = ConformanceLevel.Fragment;
// xmlSettings.OmitXmlDeclaration = true;
// XmlWriter writer = XmlWriter.Create(newXmlBuilder, xmlSettings);
StringBuilder s = new StringBuilder();
using (TextWriter newXmlWriter = StringWriter.Create(newXmlBuilder))
{
if (!string.IsNullOrEmpty(configSettings.Delimiter))
{
XsltArgumentList argsList = new XsltArgumentList();
argsList.AddParam("delimiter", "", configSettings.Delimiter);
// here is the actual problem when it transforms its create a mess and converting pound symbol and other symbols as diamond special character (encoding issue.)
requiredXslt.Transform(GetElement(xml.ToString()), argsList, newXmlWriter);
}
else
{
requiredXslt.Transform(GetElement(xml.ToString()), null, newXmlWriter);
}
}
logger.Info("XSLT applied successfully");
//replace string after transformation to validate and write to file
xml = newXmlBuilder;
return xml;
}
I want to use the desired UTF encoding while transforming it to XSLT, anyone?
As Martin Honnen already pointed out, if XSLT already has output declaration along the following line:
XSLT
<xsl:output indent="yes" method="xml" encoding="utf-8"/>
Here is c# that picks it up from the XSLT file via xslt.OutputSettings parameter:
c#
void Main()
{
const string SOURCEXMLFILE = #"e:\Temp\UniversalShipment.xml";
const string stylesheet = #"e:\Temp\UniversalShipment.xslt";
const string OUTPUTXMLFILE = #"e:\temp\UniversalShipment_output.xml";
bool paramXSLT = false;
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(stylesheet, XsltSettings.TrustedXslt, new XmlUrlResolver());
// Load the file to transform.
XPathDocument doc = new XPathDocument(SOURCEXMLFILE);
XsltArgumentList xslArg = new XsltArgumentList();
if (paramXSLT)
{
// Create a parameter which represents the current date and time.
DateTime d = DateTime.Now;
xslArg.AddParam("date", "", d.ToString());
}
using (XmlWriter writer = XmlWriter.Create(OUTPUTXMLFILE, xslt.OutputSettings))
{
xslt.Transform(doc, xslArg, writer);
}
}

Obtaining the XML encoding from an XML declaration fragment: XmlDeclaration is not supported for partial content parsing

I'm working on some code to read an XML fragment which contains an XML declaration, e.g. <?xml version="1.0" encoding="utf-8"?> and parse the encoding. From MSDN, I should be able to do it like this:
var nt = new NameTable();
var mgr = new XmlNamespaceManager(nt);
var context = new XmlParserContext(null, mgr, null, XmlSpace.None);
var reader = new System.Xml.XmlTextReader(#"<?xml version=""1.0"" encoding=""UTF-8""?>",
System.Xml.XmlNodeType.XmlDeclaration, context);
However, I'm getting a System.Xml.XmlException on the call to the System.Xml.XmlTextReader constructor with an error message:
XmlNodeType XmlDeclaration is not supported for partial content
parsing.
I've googled this error in quotes -- exactly zero results found (edit: now there's one result: this post) -- and without quotes, which yields nothing useful. I've also looked at MSDN for the XmlNodeType, and it doesn't say anything about it not being supported.
What am I missing here? How can I get an XmlTextReader instance from an XML declaration fragment?
Note, my goal here is just to determine the encoding of a partially-built XML document where I'm making the assumption that it at least contains a declaration node; thus, I'm trying to get reader.Encoding. If there's another way to do that, I'm open to that.
At present, I'm parsing the declaration manually using regex, which is not the best approach.
Update: Getting the encoding from XML documentation or from XML fragment:
Here's a way to get the encoding without having to resort to fake root, using XmlReader.Create.
private static string GetXmlEncoding(string xmlString)
{
if (string.IsNullOrWhiteSpace(xmlString)) throw new ArgumentException("The provided string value is null or empty.");
using (var stringReader = new StringReader(xmlString))
{
var settings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment };
using (var xmlReader = XmlReader.Create(stringReader, settings))
{
if (!xmlReader.Read()) throw new ArgumentException(
"The provided XML string does not contain enough data to be valid XML (see https://msdn.microsoft.com/en-us/library/system.xml.xmlreader.read)");
var result = xmlReader.GetAttribute("encoding");
return result;
}
}
}
Here's the output, with a full and fragment XML:
If you want to have System.Text.Encoding, you can modify the code to look like this:
private static Encoding GetXmlEncoding(string xmlString)
{
using (StringReader stringReader = new StringReader(xmlString))
{
var settings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment };
var reader = XmlReader.Create(stringReader, settings);
reader.Read();
var encoding = reader.GetAttribute("encoding");
var result = Encoding.GetEncoding(encoding);
return result;
}
}
Old answer:
As you mentioned, XmlTextReader's Encoding-property contains the encoding.
Here's a full Console app's source code which hopefully is useful:
class Program
{
static void Main(string[] args)
{
var asciiXML = #"<?xml version=""1.0"" encoding=""ASCII""?><note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>";
var utf8XML = #"<?xml version=""1.0"" encoding=""UTF-8""?><note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>";
var asciiResult = GetXmlEncoding(asciiXML);
var utfResult = GetXmlEncoding(utf8XML);
Console.WriteLine(asciiResult);
Console.WriteLine(utfResult);
Console.ReadLine();
}
private static Encoding GetXmlEncoding(string s)
{
var stream = new MemoryStream(Encoding.UTF8.GetBytes(s));
using (var xmlreader = new XmlTextReader(stream))
{
xmlreader.MoveToContent();
var encoding = xmlreader.Encoding;
return encoding;
}
}
}
Here's the output from the program:
If you know that the XML only contains the declaration, maybe you can add an empty root? So for example:
var fragmentResult = GetXmlEncoding(xmlFragment + "<root/>");
Good evening, here's the solution with a System.Text.Encoding as output.
I made it to be clear, and step by step.
class Program
{
static void Main(string[] args)
{
var line = File.ReadLines(YourFileName).First();
var correctXml = line + "<Root></Root>";
var xml = XDocument.Parse(correctXml);
var stringEncoding = xml.Declaration.Encoding;
var encoding = System.Text.Encoding.GetEncoding(stringEncoding);
}
}
Maybe late but you can use below code after loading it in a XmlDocument
static string getEncoding(XmlDocument xml)
{
if (xml.FirstChild.NodeType == XmlNodeType.XmlDeclaration)
{
return (xml.FirstChild as XmlDeclaration).Encoding;
}
return "utf-8";
}
If you have a byte array as input, try something like this:
private Encoding getEncoding(byte[] data)
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Ignore;
XmlDocument doc = new XmlDocument();
MemoryStream ms = new MemoryStream(data);
XmlReader reader = XmlReader.Create(ms, settings);
doc.Load(reader);
XmlDeclaration declaration = doc.ChildNodes.OfType<XmlDeclaration>().FirstOrDefault();
return Encoding.GetEncoding(declaration.Encoding);
}

Load xml and xslt from embedded resource in Saxon 9.4he

I am using Saxon 9.4 home edition (Saxon-HE 9.4 .NET) to get support for XSLT 2.0 and XPath 2.0, and XQuery 1.0 in .NET. My code crashes when I load files without an URI.
Is it possible to load xml/xsl documents without an URI related to the document loaded?
If not, is there any way to define URI for elements embedded in dll-files?
Any other solutions will also be appreciated, my only term is that the files must be loaded from within the dll-file.
My code works perfectly as long as i load xml/xsl from file:
const string sourcePath = #"C:\test\TestInvoiceWithError.xml";
const string xsltpath = #"C:\test\UBL-T10-BiiRules.xsl";
When i try to load from embedded resource the code throws an exception stating 'No base URI supplied':
Stream sourceStream = GetEmbeddedResource("TestProject1.testfiles.TestInvoice.xml");
Stream xsltStream = GetEmbeddedResource("TestProject1.testfiles.UBL-T10-BiiRules.xsl");
I have also created Uri's for resources with relative path which throws the exception 'This operation is not supported for a relative URI.':
Uri sourceUri = new Uri("/TestProject1;component/testfiles/TestInvoice.xml", UriKind.Relative);
Uri xsltUri = new Uri("/TestProject1;component/testfiles/UBL-T10-BiiRules.xsl.xml", UriKind.Relative);
Here is my code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Saxon.Api;
namespace TestProject1
{
[TestClass]
public class XsltTest
{
[TestMethod]
public void SaxonTest()
{
Stream sourceStream = GetEmbeddedResource("TestProject1.testfiles.TestInvoice.xml");
Stream xsltStream = GetEmbeddedResource("TestProject1.testfiles.UBL-T10-BiiRules.xsl");
Uri sourceUri = new Uri("/TestProject1;component/testfiles/TestInvoice.xml", UriKind.Relative);
Uri xsltUri = new Uri("/TestProject1;component/testfiles/UBL-T10-BiiRules.xsl.xml", UriKind.Relative);
const string sourcePath = #"C:\test\TestInvoiceWithError.xml";
const string xsltpath = #"C:\test\UBL-T10-BiiRules.xsl";
Processor processor = new Processor();
XdmNode input = processor.NewDocumentBuilder().Build(new Uri(sourcePath));
XsltTransformer transformer = processor.NewXsltCompiler().Compile(new Uri(xsltpath)).Load();
transformer.InitialContextNode = input;
Serializer serializer = new Serializer();
StringBuilder sb = new StringBuilder();
TextWriter writer = new StringWriter(sb);
serializer.SetOutputWriter(writer);
transformer.Run(serializer);
XmlDocument xmlDocOut = new XmlDocument();
xmlDocOut.LoadXml(sb.ToString());
XmlNodeList failedAsserts = xmlDocOut.SelectNodes("/svrl:schematron-output/svrl:failed-assert",XmlInvoiceNamespaceManager());
if (failedAsserts == null)
return;
foreach (XmlNode failedAssert in failedAsserts)
{
if (failedAssert.Attributes == null)
continue;
XmlAttribute typeOfError = failedAssert.Attributes["flag"];
if (typeOfError.Value.Equals("warning"))
{/*Log something*/}
else if (typeOfError.Value.Equals("fatal"))
{/*Log something*/}
}
}
private XmlNamespaceManager XmlInvoiceNamespaceManager()
{
IDictionary<string, string> list = new Dictionary<string, string>
{
{"xml", "http://www.w3.org/XML/1998/namespace"},
{"xsi", "http://www.w3.org/2001/XMLSchema-instance"},
{"xsd", "http://www.w3.org/2001/XMLSchema"},
{"udt","urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2"},
{"qdt","urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2"},
{"ext","urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"},
{"ccts", "urn:un:unece:uncefact:documentation:2"},
{"cbc","urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"},
{"cac","urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"},
{"inv", "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"},
{"svrl", "http://purl.oclc.org/dsdl/svrl"}
};
XmlNameTable xmlNameTable = new NameTable();
XmlNamespaceManager xmlInvoiceNamespaceManager = new XmlNamespaceManager(xmlNameTable);
foreach (KeyValuePair<string, string> ns in list)
{
xmlInvoiceNamespaceManager.AddNamespace(ns.Key, ns.Value);
}
return xmlInvoiceNamespaceManager;
}
protected static Stream GetEmbeddedResource(string path)
{
Assembly asm = Assembly.GetExecutingAssembly();
Stream stream = asm.GetManifestResourceStream(path);
return stream;
}
}
}
I think you can load from a stream with Saxon but you need to set a base URI first that would allow to load any references resources (like a DTD in an XML document or like included or imported stylesheet modules). If you are sure you don't have that then simply try e.g.
DocumentBuilder db = processor.NewDocumentBuilder();
db.BaseUri = new Uri("file:///C:/");
XdmNode input = db.Build(xsltStream);
Obviously if you need to resolve relative URIs in the XSLT that are also to be loaded as embedded resource more work is needed: you need to set up the XmlResolver to a class that supports loading the resource from an embedded resource, together with a scheme of URIs in the XSLT to indicate to the resolver that you need to load from a resource. I don't think the .NET framework provides such a kind of XmlResolver and the Uri class does not support a custom schema for that either.
Recently,I encountered this problem. And this is my solution.
private void test() {
Stream xsltStream = GetEmbeddedResource("TestSaxon.Resources.test.xsl");
Processor processor = new Processor();
DocumentBuilder db = processor.NewDocumentBuilder();
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(xsltStream);
XdmNode xdmNode = db.Build(xmlDocument);
XsltTransformer transformer = processor.NewXsltCompiler().Compile(xdmNode).Load();
var path = AppDomain.CurrentDomain.BaseDirectory;
var input = new FileInfo(path + #"\input.xml");
var output = new FileInfo(path + #"\result.xml");
var destination = new DomDestination();
using (var inputStream = input.OpenRead())
{
transformer.SetInputStream(inputStream, new Uri(input.DirectoryName));
transformer.Run(destination);
}
destination.XmlDocument.Save(output.FullName);
}
protected static Stream GetEmbeddedResource(string path)
{
Assembly asm = Assembly.GetExecutingAssembly();
Stream stream = asm.GetManifestResourceStream(path);
return stream;
}

Steps to create XML using XSD and post to URL

I was given a XSD file and sample XML file, and asked to post the XML file to a URL.
Sample XML file
<?xml version="1.0"?>
<pingRequest>
<elt></elt>
...
</pingRequest>
I'm familiar with SOAP and REST, but I have never done posting pure XML file directly. Here is what I got so far.
1) Generate C# class from XSD file
xsd.exe Test.xsd /c
2) Serialize from C# class to XML using XmlSerializer
public string SerializeObject(object obj, Type type)
{
string xml;
var xs = new XmlSerializer(type);
using (var ms = new MemoryStream())
{
xs.Serialize(ms, obj, null);
ms.Position = 0;
using (var sr = new StreamReader(memoryStream))
{
xml = sr.ReadToEnd();
}
}
return xml;
}
OR Should I use LINQ to XML to generate XML file?
3) Post XML to URL using WebClient
var client = new WebClient();
var uri = new Uri("http://www.site.com/");
string responseXML = client.UploadString(uri, requestXML);
Am I at the right track? If not, could you please point me to a right direction? Thanks in advance.
Here is my partial code so that other can use it.
First, created two classes based on XML tags using xsd.exe Test.xsd /c (for both request and response), so that I do not have to prase the XML files manually.
public pingResponse Send()
{
var pingRequest = new pingRequest
{
myelement = "test"
};
// Serialize pingRequest class to xml
var serializer = new Serializer();
string requestXml = serializer.SerializeObject(pingRequest, typeof(pingRequest));
// Post xml
var client = new WebClient();
var uri = new Uri("http://www.site.com/");
string responseXML = client.UploadString(uri, requestXML);
return (pingResponse)serializer.DeserializeObject(xml, typeof(Response));
}
public class Serializer
{
public string SerializeObject(object obj, Type type)
{
var setting = new XmlWriterSettings() {OmitXmlDeclaration = true, Indent = true};
var xml = new StringBuilder();
using (var writer = XmlWriter.Create(xml, setting))
{
var nsSerializer = new XmlSerializerNamespaces();
nsSerializer.Add(string.Empty, string.Empty);
var xmlSerializer = new XmlSerializer(type);
xmlSerializer.Serialize(writer, obj, nsSerializer);
}
return xml.ToString();
}
public object DeserializeObject(string xml, Type type)
{
var xs = new XmlSerializer(type);
var stringReader = new StringReader(xml);
var obj = xs.Deserialize(stringReader);
stringReader.Close();
return obj;
}
}
Note: I do not include the PingRequest and PingResponse classes since my member variables will not be same as yours.

Categories