Saxonica URI Resolver - xslt

we have xslt file which have multiple xsl:include /document, i am caching XsltExecutable object (the compiled xsl) and same used for transformation by multiple threads.
my question is, do we need to provide URIResolver during the compilation as well as executing transformation?, compiled style sheet (XsltExecutable object) does not include all related/dependent style sheets?.
in my case i am getting error if i do not provide URIResolver in both places. is there anyway we can keep XsltExecutable of common xsls and include it during compilation/execution phase of other xslts.
Note: we are using saxonica EE
public void transform(XsltExecutable stylesheet,Map<String, String> formatterMap, String sourceXMl, String outFileName) throws SaxonApiException {
Processor processor = new Processor(true);
Serializer out = processor.newSerializer(new File(outFileName + ".xml"));
out.setOutputProperty(Serializer.Property.METHOD, "xml");
out.setOutputProperty(Serializer.Property.INDENT, "yes");
Xslt30Transformer trans = stylesheet.load30();
trans.setURIResolver(new CigURIResolver(formatterMap));
trans.transform(new StreamSource(new StringReader(sourceXMl)), out);
System.out.println("Output written to out.xml");
}

The URIResolver on the XsltCompiler is used primarily for resolving compile-time xsl:include and xsl:import declarations. The URIResolver on the XsltTransformer is used primarily for resolving run-time calls on the doc() and document() functions.
An XsltExecutable represents an entire compiled stylesheet. If you want to compile different parts of a stylesheet independently of each other, and link the separately compiled parts together in different combinations, then you need to define it as a number of separate packages, using the new XSLT 3.0 constructs xsl:package and xsl:use-package (and not xsl:import/xsl:include). At the API level a compiled package is represented using an XsltPackage object.

Related

Saxon.Api.StaticError: 'xsl:import-schema requires Saxon-EE' with .net API

I've downloaded the .NET Saxon API. I've compiled and run the EE sample application.
Some of it required the license to be present, and I have a license file, which seemed to make it work.
I wanted to use xsl:import-schema in my xslt, and this xslt works in the Oxygen editor (which has its own EE license).
If I take the simple xslt example from the saxon sample and then attempt to get it to compile my xslt with the import-schema instruction I get:
Saxon.Api.StaticError: 'xsl:import-schema requires Saxon-EE'
That is true. However I am already explicitly referencing the Saxon EE library, so that shouldn't be an issue (see below for a clue):
Here's my code:
var samplesDir = new Uri(AppDomain.CurrentDomain.BaseDirectory);
String dir = samplesDir.LocalPath;
String sourceFile = Path.Combine(dir,"po.xml");
String styleFile = Path.Combine(dir,"po.xsl");
// Create a Processor instance.
Processor processor = new Processor();
// Load the source document
DocumentBuilder builder = processor.NewDocumentBuilder();
builder.BaseUri = new Uri(sourceFile);
XdmNode input = builder.Build(File.OpenRead(sourceFile));
XsltCompiler compiler = processor.NewXsltCompiler();
//compiler.SchemaAware = true;
compiler.BaseUri = new Uri(styleFile);
// fails on next line
Xslt30Transformer transformer = compiler.Compile(File.OpenRead(styleFile)).Load30();
// Set the root node of the source document to be the global context item
transformer.GlobalContextItem = input;
// Create a serializer, with output to the standard output stream
Serializer serializer = processor.NewSerializer();
serializer.SetOutputWriter(Console.Out);
// Transform the source XML and serialize the result document
transformer.ApplyTemplates(input, serializer);
Note that if I comment out the explicit setting to set the SchemaAware setting to true, it says:
net.sf.saxon.trans.LicenseException
HResult=0x80131500
Message=Requested feature (schema-aware XSLT) requires Saxon-EE. You are using Saxon-EE software, but the Configuration is an instance of net.sf.saxon.Configuration; to use this feature you need to create an instance of com.saxonica.config.EnterpriseConfiguration
Source=saxon9ee
StackTrace:
at net.sf.saxon.Configuration.checkLicensedFeature(Int32 feature, String name, Int32 localLicenseId)
at net.sf.saxon.PreparedStylesheet..ctor(Compilation compilation)
at net.sf.saxon.style.StylesheetModule.loadStylesheet(Source styleSource, Compilation compilation)
at net.sf.saxon.style.Compilation.compileSingletonPackage(Configuration config, CompilerInfo compilerInfo, Source source)
at net.sf.saxon.s9api.XsltCompiler.compile(Source source)
at Saxon.Api.XsltCompiler.Compile(Stream input)
at ValidateXslt.Program.Main(String[] args) in C:\Users\m_r_n\source\repos\SaxonEEExample\ValidateXslt\Program.cs:line 33
This is a better clue. It's telling me I am using saxon EE, but I need an instance of com.saxonica.config.EnterpriseConfiguration somehow.
Why am I getting this error message?
you need to tell the processor to behave like a licensed copy (seems a bit odd)
Processor processor = new Processor(true);
Simple, I'd copied an example that didnt need fancy features, but I'll leave this question as it is, just in case someone else has the same issue.

How do I use compiled stylesheets in saxon/c?

I downloaded the latest beta release of Saxon/C but I can't quite figure out how to use the compile stylesheet functionality. There's a function in the class XsltProcessor.h :-
void compile(const char* stylesheet);
that claims to compile a stylesheet but I can't see anything that would apply this compiled stylesheet to an actual source file.
The compile method allows you to supply the stylesheet as a string representation which is then compiled and cached internally for later use.
To execute the stylesheet call the method xslt->xsltApplyStylesheet("sample.xml", NULL) but supply NULL in the argument where you would pass the file name.
You could also supply the source document as a string using the methods parseXmlString and setSourceValue. In the xsltApplyStylesheet you pass NULL for the source file argument.
We will make the usability better in next release.
Have you tried the sample code here? It uses XsltProcessor.xsltApplyStylesheet(), which is documented here.
The sample code seems to have a typo in that it says test->xsltApplyStylesheet() when it means xslt->xsltApplyStylesheet().
I'm not sure what the compile() method does with its results, or how to use them.

Roslyn: SyntaxWalker through 2 different documents

I have a solution with two different projects. I use SyntaxWalker to process some stuff in ProjectA.Class1. However, ProjectA.Class1 has reference ProjectB.Class2.
Is there way to allow the syntax walker to traverse also through external classes? I can't even do it when both classes are in the same project but in different files (documents). It always goes through the same document. If both classes are in the same file then it works. If I extract them to separate ones, it doesn't...
I am working on a test coverage tool. A user click on the method in VS and then:
I use rewriter to add static variables to each branch.
I run the code so the static variables are set if branch was covered.
I wonder how should I configure a syntax walker\rewriter to recognize other classes in the same solution.
You're going to need access to the Symbol API. A simple rule of thumb I try to go by:
The Syntax API is for individual files
The Symbol API allows you to work with information that spans across files.
You've mentioned in the comments that you'd like to traverse methods and figure out some information about each method declaration. Here's some (naive) code that should get you started with the symbol API.
I've assumed you've got access to a Project that you're analyzing.
Project myProject;
public void ProcessMethod(MethodDeclarationSyntax method)
{
//Get the semantic model
var filePath = method.SyntaxTree.FilePath;
var containingDocument = myProject.Documents.Where(n => n.FilePath == filePath).Single();
var model = containingDocument.GetSemanticModelAsync().Result;
//...
//Do your processing on the current method here...
//...
//Process the invoked methods.
var invocations = method.DescendantNodes().OfType<InvocationExpressionSyntax>();
foreach(var invocation in invocations)
{
var invokedSymbol = model.GetSymbolInfo(invocation).Symbol; //Might be null
var invokedSymbolSyntax = (MethodDeclarationSyntax)invokedSymbol.DeclaringSyntaxReferences.First().GetSyntax(); //Partial methods might be declared in multiple places
ProcessMethod(invokedSymbolSyntax);
}
}
Note:
This approach doesn't handle constructors, destructors, properties, expression-bodied members and any other members I've forgotten. But it should be enough to get you started and introduce you to the symbol API.
Recursion will bite you.
You won't process implementations of interfaces. You'll have to look into the SymbolFinder for that.

design pattern for "save"

I'm currently working on a "save" mechanism, which allows a user to save the project his working on on hard disc. The output will be a XML file containing all kinds of data.
Now our project structure is about to change and we need to write a new xml file (create a new save method).
So now here comes the challenge: When saving I want the user to be able to choose which file format he will be creating (version1 (old) or version2 (new)).
Does anyone now how to achieve that? Is there a suitable design pattern around?
Remarks:
- The data we are saving can be seen as unrelated blocks, so it would actually be easy to exchange an old block with a new one.
- The whole goal of the thing is, it should be readable again when loading an old project. (I assume this can be done by tags, and just react on tags when loading?)
This sounds like a good application for the Strategy pattern.
You would create an abstract base class FileFormat (the Strategy interface) with two virtual functions, projectToXml and xmlToProject, which are supposed to turn your internal project representation into XML or vice versa.
Then you create two implementing subclasses FileFormatNew and FileFormatLegacy (these are the concrete strategies).
Your save functions would then additionally require an instance of FileFormat, and call the corresponding method of that object to do the data conversion. Your load function could choose the strategy to use by examining the XML tree for something which tells it which version it is.
And when you ever need to support another file format, you just have to create a new class which is a subclass of FileFormat.
Addendum after the exchange in the comments
When you are going to have a lot of versions with very small differences and you still want to use the Strategy pattern, you could make the FileFormat a composite of multiple strategies: A CircleStragegy, a RectangleStrategy, a LineStrategy etc.. In that case I wouldn't use different classes for different versions of the FileFormat. I would create a static factory function for each version which returns a FileFormat with the Strategy objects used in that version.
FileFormat FileFormat::createVersion1_0() {
return new FileFormat(
new LineStrategyOld(),
new CircleStrategyOld(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_1() {
// the 1.1 version introduced the new way to save lines
return new FileFormat(
new LineStrategyNew(),
new CircleStrategyOld(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_2() {
// 1.2 uses the new format to save circles
return new FileFormat(
new LineStrategyNew(),
new CircleStrategyNew(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_3() {
// 1.3 uses a new format to save rectangles, but we realized that
// the new way to save lines wasn't that good after all, so we
// returned to the old way.
return new FileFormat(
new LineStrategyOld(),
new CircleStrategyNew(),
new RectangleStragegyNew()
);
}
Note: In real code you would of course use more descriptive suffixes than "Old" and "New" for your strategy class names.

Invalid factory configuration javax.xml.transform.TransformerConfigurationException: Failed to compile stylesheet

When i use the combination of XSLT 1.0 and saxon9he.jar for my xml to pdf conversion using xslt and xsl-fo, i am getting the exception that Invalid factory configuration
javax.xml.transform.TransformerConfigurationException: Failed to compile stylesheet.
My lib folder contains the saxon9he.jar for xpdl to xml conversion using xslt2 and xalan.2.7.1.jar for xml to pdf converson.
The first part is working fine but the second part is getting exception due to saxon.jar's (trasnformer,transfor(arg1, arg2))presence is dominating the xalan.jar (transfor(a1,a2). But the second part of xml to pdf conversion (xalan.jar) is working fine if i removed the saxon9he.jar from my lib folder.
i am anticipating the good respomse from experts. plz find my sample code below.
thnx in advance...
out = new FileOutputStream(pdf);
BufferedOutputStream out1 = new BufferedOutputStream(out);
Fop fop = newFop(MimeConstants.MIME_PDF, out1);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
Source src = new StreamSource(fo);
Result res = new SAXResult(fop.getDefaultHandler());
// i am getting exception at following line.
transformer.transform(src, res);
If you need to use Saxon and Xalan in the same application, then don't rely on TransformerFactory.newInstance(), which loads the first XSLT engine it finds. You can always load the one you want explicitly by instantiating its specific implementation of the TransformerFactory interface.