I'm using the .Net framework's XslCompiledTransform class as the XSLT processor (in other words Xslt 1.0).
My requirement is that I want to convert an XML file to an Excel file (xls file) using XSLT 1.0 and .Net [4.0].
For simplicity and since this is just test code, I'm just considering some simple hard-coding on my Xsl file.
Specifically, my two questions are:
I've tried a bunch of things, yet I can't see my Excel sheet's worksheet named to "wAbc" which is what I'm trying to name it. I see the worksheet name as my file name. Additional worksheets are not generated as well. Below is my XSL file
Additionally, since this is test code, I can't see the data outputted on different rows unless I use HTML tags . What I see is: AbcNext line instead of
Abc
Nextline
So what am I doing wrong? Thank you in advance for your time and help.
I set the content type for my file response as
application/vnd.ms-excel
Here is my test Xsl file:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<xsl:template match="/">
<xsl:processing-instruction name="mso-application">progid='Excel.Sheet'</xsl:processing-instruction>
<Workbook>
<Worksheet ss:Name="wAbc">
<Table ss:ExpandedColumnCount="2" x:FullColumns="1" x:FullRows="1" ss:DefaultRowHeight="15">
<Column ss:AutoFitWidth="20" ss:AutoWidth="65"></Column>
<Row>
<Cell>
<Data ss:Type="String">Abc</Data>
</Cell>
</Row>
<Row>
<Cell>
<Data ss:Type="String">Next line</Data>
</Cell>
</Row>
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
</WorksheetOptions>
</Worksheet>
</Workbook>
</xsl:template>
</xsl:stylesheet>
You are using Excel XML as the format here (so, not strictly an XLS file, which is binary).
But in any case, I can see two issues with the Excel XML you are currently outputting. Firstly, I think the ss:AutoFitWidth attribute on the Column element needs to be set to 1 (or 0). I don't think 20 is a valid value.
See http://msdn.microsoft.com/en-us/library/aa140066(v=office.10).aspx for the list of possible values.
Addtionally, I think you may (although I am not 100% sure on this) need to set the ss:ExpandedRowCount on the Table element as well as the ss:ExpandedColumnCount.
See if changing one or both of these fixes your errors.
Excel XLS files use a Microsoft proprietary binary format - no way to generate that with an XSLT.
The (relatively) new XSLX format is a set of XML files that are ZIPped together, so in principle you can generate these files with an XSLT, and then ZIP them to generate the final file - still not very easy. To see these files simply un-ZIP an XSLX file.
I suggest you generate a simpler format - either a CSV or an intermediate XML- and then import it into Excel.
Related
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
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 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.
I have an XML file, I need to extract values from it, and put them in another XML file.
Questions:
Another person is creating the "schema" for the resulting XML file. Is there something that person can give me that will automate the inserting of the values? Do I even need to extract anything from the XML, or can something like a XSLT just do all the transformation?
Is there a problem with this XML structure below? I tried using xsd2code to generate objects but nothing will load when I use the LoadFromFileMethod - I read an article that wasn't very specific but said "nested parents" cause problems for XSD.exe and xsd2code.
<Section>
<Form id="1"...>
<Control id="12523"..> <--Some have this some don't
<Property name="Color">Red</Property>
<Property name="Size">Large</Property>
</Control>
</Form>
<Form id="2"...>
<Property name="Color">Blue</Property>
<Property name="Size">Large</Property>
</Form>
<Form id="3"...>
<Property name="Color">Red</Property>
<Property name="Size">Small</Property>
</Form>
</Section>
Thank you for any guidance!
XSLT is the tool for XML transformation.
As far as your XML goes, in a lot of applications you should replace this:
<Property name="Color">Red</Property>
with:
<Color>Red</Color>
Some reasons:
If you want to write a schema that restricts an element's content in some way (e.g. to one of a list of values), the element must be identifiable by its name; you can't write one schema for a Property element with a name attribute equals "Color" and another schema for a Property element whose name attribute equals "Size".
It's easier to write XPath predicates if your element names are meaningful. For instance, Form[Color = 'Red'] is a lot easier to write (and read) than Form[Property[#name='Color' and .='Red']]
The above is also true if you're writing Linq queries against the XML, in pretty much the same manner. Compare Element.Descendants("Color") with Element.Descendents("Property").Where(x => x.Attributes["name"] == "Color").
There are applications where it's appropriate to have generically-named elements, too; the above argument's not definitive. But if you're going to do that, you should have good reasons.
XLST is the best way to transform xml from one schema to another. Thats exactly what it was built to do. http://w3schools.com/xsl/default.asp is an excellent XSLT tutorial. All you really need is the schema, or a few examples of his xml to write your xslt file.
Also, your xml looks fine/well-formed to me.
XSLT is probably the solution if you just want to transform it, but if you need to do anything with the values in code then LINQ to Xml will make your task much easier.
I'd use XSLT for this, here's a small example to get you started.
Copy this sample code to an empty c# project:
static void Main(string[] args) {
const string xmlPath = "source.xml";
const string xslPath = "transform.xsl";
const string outPath = "out.xml";
try {
//load the Xml doc
var xmlDoc = new XPathDocument(xmlPath);
//load the Xsl
var xslDoc = new XslCompiledTransform();
xslDoc.Load(xslPath);
// create the output file
using (var outDoc = new XmlTextWriter(outPath, null)) {
//do the actual transform of Xml
xslDoc.Transform(xmlDoc, null, outDoc);
}
}
catch (Exception e) {
Console.WriteLine("Exception: {0}", e.ToString());
}
}
Write your example xml code above into source.xml file and put the following xsl code into transform.xsl file:
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" method="xml" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="Section">
<OtherSection>
<xsl:apply-templates />
</OtherSection>
</xsl:template>
<xsl:template match="Form">
<OtherForm>
<xsl:attribute name="id">
<xsl:value-of select="#id" />
</xsl:attribute>
<xsl:apply-templates />
</OtherForm>
</xsl:template>
<xsl:template match="Control">
<OtherControl>
<!-- converts id attribute to an id tag -->
<id>
<xsl:value-of select="#id" />
</id>
<xsl:apply-templates />
</OtherControl>
</xsl:template>
<xsl:template match="Property">
<OtherProperty>
<!-- converts name attribute to an id attribute -->
<xsl:attribute name="id">
<xsl:value-of select="#name" />
</xsl:attribute>
<xsl:value-of select="."/>
</OtherProperty>
</xsl:template>
</xsl:stylesheet>
The resulting out.xml should give you an idea of how the xsl is doing the work and hopefully get you started.
For more info on XSLT look up the tutorial on W3Schools.
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.