Transformation from XML to Excel 2010 file - c#

How do I create a Template for the XSLT transformation from XML file to Excel 2010 file or Word 2010 ?
This is our Template for the Transformation in Execel 2003. But now I need it for 2010 ?
Thanks for Help !
<xsl:stylesheet xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xslex="urn:XsltExtension"
xmlns:html="http://www.w3.org/TR/REC-html40"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:x="urn:schemas-microsoft-com:office:excel"
version="2.0">
<xsl:output method="xml" indent="yes" />
<xsl:output method="xml" version="1.0"/>
<xsl:template match="/NewDataSet">
<xsl:variable name="elements" select="xs:schema/xs:element/xs:complexType/xs:choice/xs:element/xs:complexType/xs:sequence/*" />
<xsl:variable name="columnAppearances" select="ColumnAppearances/*" />
<xsl:processing-instruction name="mso-application">
<xsl:text>progid="Excel.Sheet"</xsl:text>
</xsl:processing-instruction>
<Workbook>
<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office" />
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
</xsl:styleshee>

The open XML format used by Excel 2007+ consists of many XML's inside a ZIP package. The overall format is very different than the single-file XML format you mention. If you have a working solution now, I suggest you leave it as is, and use interop to convert it to a newer format. If you want to avoid interop, then you should use the OpenXML SDK instead. Doing it with XSLT would be very painful, if not impossible, and it is certainly off-topic here because it's a vast amount of work.

Related

Problems with OpenXML 2.5 XSL Transformation Word 2013 C#

Can anyone help me out on this problem?
I haven't done anything with OpenXML before and it has me stumped!
I have a Word Document which is an invoice.
In this document, I have the usual headers etc, plus the 'fields' which need to be populated with data from my XML dataset from SQLServer.
I took a copy of the word/document.xml from the docx and made the recommended changes to the file to convert it into an XSLT file.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
becomes
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:n2="urn:hl7-org:v3"
exclude-result-prefixes="n2 xs xsi xsl">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
and the file is terminated with
</xsl:template>
</xsl:stylesheet>
Then, I changed some of my 'fields' to show where I wanted the data to be merged.
All well and good......
When I ran it, I got a new file which looked OK but would not open in Word 2013. I pulled the document.xml out of the docx and tried to open that. This gave me an Unspecified Error Line 1 Column 1257.
I have since tried all sorts of things, including creating an XSLT with no merge fields, just the headers and footers set up, and I get the same thing.
I have tried several different headers with differing complexity and always get the same error.
When I trace the error, it is in this tag line
<w:document xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 wp14">
which finishes with column 1257:
mc:Ignorable="w14 w15 wp14">
I have checked that the namespaces are all declared but I cannot see, or understand, what is going wrong
Any ideas?
Thanks

Saxon XSLT: Serializer producing weird indents

I'm using Saxon HE 9.5.1.8 to transform an XML to another XML file.
My problem is that the XML content written by the Serializer() class of Saxon prints out several additional indents that I don't want to have in there. I'm assuming that this is "wrong" because I got the expected output when using the DomDestination() class (but then the outer XML document information is missing) or other XSL transformers like the one that is shipped with Visual Studio / .NET Framework.
This is the input XML:
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>$44.95</price>
<publish_date>2000-10-01</publish_date>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>$5.95</price>
<publish_date>2000-12-16</publish_date>
</book>
This is the XLST file:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="book">
<book>
<xsl:copy-of select="#*|book/#*" />
<xsl:for-each select="*">
<xsl:attribute name="{name()}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:for-each>
</book>
</xsl:template>
</xsl:stylesheet>
That is the expected output:
<?xml version="1.0" encoding="utf-8"?>
<catalog>
<book id="bk101" author="Gambardella, Matthew" title="XML Developer's Guide" genre="Computer" price="$44.95" publish_date="2000-10-01" />
<book id="bk102" author="Ralls, Kim" title="Midnight Rain" genre="Fantasy" price="$5.95" publish_date="2000-12-16" />
</catalog>
And that is the output when using Saxon:
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<book id="bk101"
author="Gambardella, Matthew"
title="XML Developer's Guide"
genre="Computer"
price="$44.95"
publish_date="2000-10-01"/>
<book id="bk102"
author="Ralls, Kim"
title="Midnight Rain"
genre="Fantasy"
price="$5.95"
publish_date="2000-12-16"/>
</catalog>
Does anybody know how to suppress or modify this behavior of Saxon? That is the C# code that is used to call the Saxon API:
public Stream Transform(string xmlFilePath, string xsltFilePath)
{
var result = new MemoryStream();
var xslt = new FileInfo(xsltFilePath);
var input = new FileInfo(xmlFilePath);
var processor = new Processor();
var compiler = processor.NewXsltCompiler();
var executable = compiler.Compile(new Uri(xslt.FullName));
var destination = new Serializer();
destination.SetOutputStream(result);
using(var inputStream = input.OpenRead())
{
var transformer = executable.Load();
transformer.SetInputStream(inputStream, new Uri(input.DirectoryName));
transformer.Run(destination);
}
result.Position = 0;
return result;
}
Try setting http://saxonica.com/documentation9.5/extensions/output-extras/line-length.html to a very large value to avoid that attributes are put on a new line: <xsl:output xmlns:saxon="http://saxon.sf.net/" saxon:line-length="1000"/>.
Your goal of having multiple processors produce output in the same format is hopelessly misguided. That's especially so if you choose indented output: the spec leaves it entirely to implementations how to do indentation, saying only that the goal is to make it human-readable. (And placing constraints on where extra whitespace can be inserted.)
I'm sorry you don't find Saxon's way of wrapping long attribute lists pleasing, but it is entirely within the letter and the spirit of the specification. Without it, if you have an element with eight namespace declarations, you can easily get a line that is 400 characters long, which I certainly don't regard as human-readable.
There are many reasons that comparing two XML documents lexically is never going to work. For example, the attributes can be in a different order. There are two ways of comparing XML: convert the documents into canonical form using a "Canonical XML" processor, or compare them at the tree level for example by using the XPath 2.0 deep-equal() function. Ideally (especially if you want to know where the differences are, rather than just whether differences exist), use a specialist XML comparison tool such as DeltaXML.
For what it's worth, when we do unit testing, we first attempt a lexical comparison of the results. If that fails, we parse both documents and compare them using saxon:deep-equal(), which is a modified form of the deep-equal() function that gives fine control over the comparison rules, e.g. handling of whitespace and handling of namespaces.

How to get an absolute path to the directory of the XSL file?

My Schema.xsd file is located in the same directory with the .xsl file. In the .xsl file I would like to generate a link to Schema.xsl in the generated output. The generated output is located in different directories. Currently I do it like this:
<xsl:template match="/">
<root version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../Schema.xsd">
<!-- . . . -->
However this forces the generated output to be located 3 levels under the directory of Schema.xsd. I would like to generate an absolute path to the schema in the output, so the output could be located anywhere.
Update. I use XSLT 1.0 (XslCompiledTransform implementation in .NET Framework 4.5).
XSLT 2.0 Solution
Use the XPath 2.0 function, resolve-uri():
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"
omit-xml-declaration="yes"
encoding="UTF-8"/>
<xsl:template match="/">
<root version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="{concat(resolve-uri('.'), 'Schema.xsd')}">
</root>
</xsl:template>
</xsl:stylesheet>
Yields, without parameter passing and regardless of the input XML:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="1.0"
xsi:noNamespaceSchemaLocation="file:/c:/path/to/XSLT/file/Schema.xsd"/>
This is a sketch of how to do it (also see Passing parameters to XSLT Stylesheet via .NET).
In your C# code you need to define and use a parameter list:
XsltArgumentList argsList = new XsltArgumentList();
argsList.AddParam("SchemaLocation","","<SOME_PATH_TO_XSD_FILE>");
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load("<SOME_PATH_TO_XSLT_FILE>");
using (StreamWriter sw = new StreamWriter("<SOME_PATH_TO_OUTPUT_XML>"))
{
transform.Transform("<SOME_PATH_TO_INPUT_XML>", argsList, sw);
}
Your XSLT could be enhanced like this:
...
<xsl:param name="SchemaLocation"/> <!-- this more or less at the top of your XSLT! -->
...
<xsl:template match="/">
<root version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="{$SchemaLocation}">
...
...
</xsl:template>
....

Validate xsl fo in xslt stylesheet

I have a little problem with validating xml, xslt in details.
I have an xslt stylesheet that transforms xml data source to xsl:fo document.
Something like this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:template match="/">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns="http://www.w3.org/1999/xhtml">
<fo:layout-master-set>
<fo:simple-page-master margin-top="25mm" margin-bottom="25mm" margin-left="25mm" margin-right="25mm" page-width="210mm" page-height="297mm" master-name="simplePageLayout">
<fo:region-body region-name="xsl-region-body" column-gap="0.25in" />
<fo:region-before region-name="xsl-region-before" display-align="after" extent="0.1mm" padding-top="0pt" padding-left="0.4in" padding-right="0.4in" padding-bottom="0pt" />
<fo:region-after region-name="xsl-region-after" display-align="before" extent="0.4in" padding-top="4pt" padding-left="0.4in" padding-right="0.4in" padding-bottom="0pt" />
</fo:simple-page-master>
<fo:page-sequence-master master-name="default-sequence">
<fo:repeatable-page-master-reference master-reference="simplePageLayout" />
</fo:page-sequence-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="default-sequence">
<fo:flow flow-name="xsl-region-body">
<fo:block font-family="Segoe UI" color="#000000" font-size="9pt" />
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
What I want to do is to validate written xsl:fo elements, ignoring xsl tags. Is it possible?
For now I use dtd validation (I have xsd schema too) for validating Fo, but it gives me an error on each xsl tag.
Summary:
Is it possible to validate only fo elements against the schema, ignoring xsl tags, and how should I do it? Maybe a code snippet in C#, or a hint how to modify documents?
What you want to do the schema validation against is the output after you do the transform, not against the XSLT document. When you run the XSLT transformation against the input XML, the resulting output shouldn't contain any of the XSL tags.

How can I render custom XSL controls in my XSLT file with C#?

I'm using C# to translate a XML file to HTML with the use of XSLT.
I use an Extension object to render my own code:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:widget="urn:serverTime"
>
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<xsl:value-of select="demo:printTime()"/>
</xsl:template>
and in my C#:
XsltArgumentList myList = new XsltArgumentList();
myList.AddExtensionObject("demo:serverTime", new ServerTime());
transform.Transform(document, myList, writer);
This works perfectly. However, I would like to create my own custom tags like:
<demo:printTime />
This doesn't work: the tag is printed to the output without being rendered. How can I make this work so I can use my own tags?
You can't do this. XSLT does not support "custom tags".
If you want to print out anything that is not a literal value, then it must be the result of a function call, wrapped in <xsl:value-of/>.

Categories