I'm using Asp.net to create a csv file that the user can open directly in excel. I want to make it possible to show the download popup and for the user to choose "Open with Excel" and that will open the file in excel.
The code to create the csv:
Response.Clear();
Response.AddHeader("content-disposition", string.Format("attachment; filename={0}.csv", "test"));
Response.ContentType = "text/csv";
Response.Write("Year, Make, Model, Length\n1997, Ford, E350, 2.34\n2000, Mercury, Cougar, 2.38");
Response.End();
Excel needs to understand that "Year", "Make", etc should all be different columns. That doesn't seem to work with the csv I'm creating, everything is just in the same column. It shows up like this:
http://oi54.tinypic.com/2evyb0k.jpg
The only way to get it working with excel is to use the "Text Import Wizard". Then everything shows up in different columns like it should.
As I said what I need is to create a spreadsheet (it doesn't need to be csv), it should just be easy for the user to open in excel or whatever they are using to start working with it. How would you solve this? Thanks!
Not sure why it doesn't work like that - it does for me, but at a minimum try quoting the data:
Response.Write("\"Year\", \"Make\", \"Model\", \"Length\"\n\"1997\", \"Ford\", \"E350\", \"2.34\"\n\"2000\", \"Mercury\", \"Cougar\", \"2.38\"");
Excel can also import XML, google "<?mso-application progid="Excel.Sheet"?>" for the format. Or just save an excel spreadsheet as XML to see an example. Excel XML files can be named ".xls" and it will be able to open them directly.
Finally, you can use NPOI in .NET to manipulate excel spreadsheets in the native format: http://npoi.codeplex.com/
For XML you can also use a wrapper class I wrote that encapsulates this in a simple C# object model: http://snipt.org/lLok/
Here's some pseudocode for using the class:
XlsWorkbook book = new XlsWorkbook();
XlsWorksheet ws = new XlsWorksheet();
ws.Name = "Sheet Name";
XlsRow row;
XlsCell cell;
foreach (datarow in datasource) {
row = new XlsRow();
foreach (datavalue in datarow) {
cell = new XlsCell(datavalue.ToString());
cell.DataType = datavalue is numeric ? DataTypes.Numeric | DataTypes.String;
row.Cells.Add(cell);
}
ws.Rows.Add(row);
}
wkb.Worksheets.Add(ws);
Response.Write(wkb.XmlOutput());
Or just create your own method, here are the basics.
Create the header this way:
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append("<?xml version=\"1.0\"?>\n");
sb.Append("<?mso-application progid=\"Excel.Sheet\"?>\n");
sb.Append(
"<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\" ");
sb.Append("xmlns:o=\"urn:schemas-microsoft-com:office:office\" ");
sb.Append("xmlns:x=\"urn:schemas-microsoft-com:office:excel\" ");
sb.Append("xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\" ");
sb.Append("xmlns:html=\"http://www.w3.org/TR/REC-html40\">\n");
sb.Append(
"<DocumentProperties xmlns=\"urn:schemas-microsoft-com:office:office\">");
sb.Append("</DocumentProperties>");
sb.Append(
"<ExcelWorkbook xmlns=\"urn:schemas-microsoft-com:office:excel\">\n");
sb.Append("<ProtectStructure>False</ProtectStructure>\n");
sb.Append("<ProtectWindows>False</ProtectWindows>\n");
sb.Append("</ExcelWorkbook>\n");
From there, add to your output string by creating nodes using this basic structure:
<Worksheet ss:Name="SheetName">
<Table>
<Row>
<Cell>
<Data ss:Type="DataType">Cell A1 Contents Go Here</Data>
</Cell>
</Row>
</Table>
</Worksheet>
Within a <Row>, each <Cell> element creates a new column. Add a new <Row> for each spreadsheet row. The DataType for <Data> can be "String" or "Number".
Related
I have an excel file that contains all the filenames of the Images. The path of these images are stored in an Observable Collection via <File> class which came from the folder that contains all of the images. My goal is to create a hyperlink of these filenames by matching it through the pool of image file collection.
I would like to ask if how can I iterate faster through a large collection of file classes in order to get their paths easily.
For example:
Image name from Excel :
ABC_0001
The Full path from the collection must be:
C:\Users\admin\Desktop\Images\ABC_0001.jpg
In order to get their full path, I perform the iteration through Stream.
My procedures:
Extract data using Apache POI.
Stream through the Image Collection by converting each data into
their base filenames vs extracted data.
Get the result and store the fullpath on the object via
getAbsolutePath().
Code:
//storage during iteration
ObservableList<DetailedData> dataCollection = FXCollections.observableArrayList()
//Image collection containing over 13k Images listed via commons-io
ObservableList<File> IMAGE_COLLECTION = FXCollections.observableArrayList(FileUtils.listFiles(browsedFOLDER, new String[]{"JPG", "JPEG", "TIF", "TIFF", "jpg", "jpeg", "tif", "tiff"}, true));
//Sheet data
Sheet sheet1 = wb.getsheetAt(0);
for (Row row: sheet1)
{
DetailedData data = new DetailedData();
//extracted data from excel
String FILENAME = row.getCell(0,Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).getStringCellValue();
//to be filled up based on stream result.
String IMAGE_SOURCE = null;
//stream code with the help of commons-io
File IMAGE = IMAGE_COLLECTION.stream().filter(e -> FilenameUtils.getBaseName(e.getName()).toLowerCase().equals(FILENAME.toLowerCase())).findFirst().orElse(null);
if (IMAGE != null)
IMAGE_SOURCE = IMAGE.getAbsolutePath();
data.setFileName(FILENAME);
data.setFullPath(IMAGE_SOURCE);
dataCollection.add(data);
}
Result:
Excel rows = 9,400
Image Files = 13,000
Iteration Time = 120,000ms
Are the results should appear normal or it can become faster?
I tried using parallelStream() and the results went faster but it consumes higher CPU usage.
This code should speed your code up a lot, but there are a few questions about your code.
ObservableList<DetailedData> dataCollection = FXCollections.observableArrayList() Why are you using ObservableList? Why is this a list of DetailedData and not File. Given that detailed data has setFileName and setFullPath. File already has these.
ObservableList<File> IMAGE_COLLECTION = FXCollections.observableArrayList(FileUtils.listFiles(browsedFOLDER, new String[]{"JPG", "JPEG", "TIF", "TIFF", "jpg", "jpeg", "tif", "tiff"}, true)); Why ObservableList?
These two are small things, but I am curious.
So what I think you should do is use a Map. Your code should look something like the code below.
//storage during iteration
List<DetailedData> dataCollection = new ArrayList();
//Image collection containing over 13k Images listed via commons-io
List<File> IMAGE_COLLECTION = new ArrayList(FileUtils.listFiles(new File("C:\\Users\\blj0011\\Pictures"), new String[]{"JPG", "JPEG", "TIF", "TIFF", "jpg", "jpeg", "tif", "tiff"}, true));
//Use this to map file name to file
Map<String, File> map = new HashMap();
//Use this to add data to the map
IMAGE_COLLECTION.forEach((file) -> {map.put(file.getName().substring(0, file.getName().lastIndexOf(".")).toLowerCase(), file);});
for (Row row: sheet1)
{
//extracted data from excel
String FILENAME = row.getCell(0,Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).getStringCellValue();
//If the map contains the file name, create `DetailedData` object. Then set data. Then add object to datacollection list.
if (map.containsKey(FILENAME.toLowerCase()))
{
DetailedData data = new DetailedData();
data.setFileName(FILENAME);
data.setFullPath(map.get(FILENAME.toLowerCase()).getAbsolutePath());
dataCollection.add(data);
}
}
Comments in the code
I still believe this could be cleaned up a little more if you used List<File> dataCollection = new ArrayList()
If you really want to speed up your search, you should try not to do things repeatedly which could just be done once. For example you could use two loops. The first to prepare your search and the second to actually do the search. Inside your filter you call FilenameUtils.getBaseName and two time a conversion to lower case. It would be better to do these things only once in the first loop and store the resulting Strings in a list. In the second loop you then do the search on this list.
I am also wondering why you use ObservableLists here. A simple List would do as well.
I've tested another approach in this slow iteration.
It seems that the cause is declaring the Stream repeatedly inside the foreach.
I tried using Baeldung's solution <Supplier> and declared it outside the loop together with parallelStream()
Sample Code:
Supplier<Stream<File>> streamSupplier = () -> imageCollection.parallelStream();
for (Row row : sheet)
{
File IMAGE = streamSupplier.get().filter(e -> FilenameUtils.getBaseName(e.getName()).toLowerCase().equals(FILENAME.toLowerCase())).findFirst().orElse(null);
if (IMAGE != null)
IMAGE_SOURCE = IMAGE.getAbsolutePath();
}
Result went 45000ms
Please correct me if my approach was not right.
I'm newbie in indesign scripting stuffs.So I apologise as I couldn't post my trials.
Objective:
I have an indd document which will have figure caption,label etc. I need to copy content(figure which is editable) from other indd file to this document where related figure label exists.
For example:
sample.indd
Some text
Fig.1.1 caption
some text
I need to copy the content of figure1.indd and paste into the sample.indd document where Fig.1.1 string exists and so on. Now I'm doing it manually. But am supposed to automate this.
So, I need some hint how to acheive it using extendscript?
I have found something like below to do this, but I don't have any clue to develop it further and also am not sure whether this approach is correct to get my result. Pls help me
myDocument=app.open(File("file.indd"),false); //opening a file to get the content without showing.
myDocument.pages.item(0).textFrames.item(0).contents="some text";
//here I could set the content but I don't knw how to get the content
// ?????? Then I have to paste the content into active document.
I found the script for my requirement.
var myDoc = File("sample.indd");//Destination File
var myFigDoc = File("fig.indd");//Figure File
app.open(File(myFigDoc));
app.activeDocument.pageItems.everyItem().select();
app.copy();
app.open(File(myDoc));
app.findGrepPreferences = app.changeGrepPreferences = null;
app.findGrepPreferences.findWhat = "FIG. 1.1 ";//Figure caption text
//app.findGrepPreferences.appliedParagraphStyle = "FigureCaption";//Figure Caption Style
myFinds = app.activeDocument.findGrep();
for(var i=0;i<myFinds.length;i++){
myFinds[i].insertionPoints[0].contents="\r";
myFinds[i].insertionPoints[0].select();
app.paste();
}
app.findGrepPreferences = app.changeGrepPreferences = null;
If acceptable for you, you can place an indesign file as link (place…). So a script could try to catch the "fig…" strings and do the importation.
Have a look at scripts that use finGrep() and place() command.
There is requirement of Excel file upload on .aspx page and reading data and store that in database. In the excel user can format specific word or sentence in a any cell. We want preserve those formatting in form of HTML tag. So we want to reach data with formatting with html tag. How it can be achieved.
Probaly the best way would be to use the Excel interop assemblies under Microsoft.Office.Interop.Excel namespace. The code would be something like this:
Excel.Application excel = new Excel.Application();
excel.Workbooks.Open(fileName);
Excel.Worksheet activeWorksheet = ExcelApp.ActiveSheet;
for (int i = 1; i < 100; i++){
for (int j = 1; j < 100; j++){
Excel.Range currentCell = activeWorksheet.Cells[i, j];
// formating
var fontFamily = currentCell.Font.Name;
var italics = currentCell.Font.Italic;
var color = currentCell.Font.Color;
}
}
This opens an excel file and loops trough first 99 rows and columns.
But this could be too intensive since it would open Excel for each document - not sure what kind of performance is required. There are other libraries available that offer simple reading and writing to Excel, but I'm not sure if they offer reading the formats and things like that. You can find some more info about those tools here: Import and export excel. I just checked and it seems EPPPlus support cell styling, so that might be an alternative.
I m trying to build a function that will retrieve 'some' SQL data from multiple tables, and store it in a file in the XML format.
If I do it with C#, is it as simple as:-
SQL statement,
retrieve data,
store data in a string list,
and then WriteXml (xmlFile, variable where data is stored) ??
Can any one show me an example?
I was looking at:-
WriteXml () and WriteXmlSchema() functions in C#
string xmlFile = Server.MapPath("Employees.xml");
ds.WriteXml(xmlFile, XmlWriteMode.WriteSchema);
Also, will xmlSerialization be something I need to take a look at?
Sample SQL query.
SqlConnection Connection1 = new SqlConnection(DBConnect.SqlServerConnection);
String strSQL1 = "SELECT xxx.MEMBERKEY, xxx.MEMBID, xyz.HPCODE, convert(varchar, OPFROMDT, 101) as OPFROMDT"
+ ", convert(varchar, OPTHRUDT, 101) as OPTHRUDT FROM [main].[dbo].[yyy] INNER JOIN [main].[dbo].[xxx] ON xxx.MEMBERKEY = yyy.MEMBERKEY "
+ "and opthrudt >= opfromdt INNER JOIN [main].[dbo].[xyz] ON yyy.HPCODEKEY = xyz.HPCODEKEY where MembID = #memID";
SqlCommand command1 = new SqlCommand(strSQL1, Connection1);
command1.Parameters.AddWithValue("#memID", memID);
SqlDataReader Dr1;
Connection1.Open();
Dr1 = command1.ExecuteReader();
while (Dr1.Read())
{
HPCODEs.Add((Dr1["HPCODE"].ToString()).TrimEnd());
OPFROMDTs.Add((Dr1["OPFROMDT"].ToString()).TrimEnd());
OPTHRUDTs.Add((Dr1["OPTHRUDT"].ToString()).TrimEnd());
}
Dr1.Close();
There are so many approaches to this.
For one, you can invest some time and use SQL built in XML capabilities to query and get an XML document directly which then you can serialize straight into a file. A very basic example could be found here. Then you would use the DataReader's GetSqlXml method, something like this
SqlDataReader r = cmd.ExecuteReader();
SqlXml data = r.GetSqlXml(0);
XmlReader xr = data.CreateReader();
Maybe another option is to read from the sql data reader into DTO (data transfer objects). This is probably the tried and true method. And then once you have a list of DTO's you can use .NET's serialization (DataContractSerializer) to serialize to XML.
I would highly recommending looking at a tool like this:
http://msdn.microsoft.com/en-us/library/x6c1kb0s(v=vs.80).aspx
This will generate .net classes for you if you have an xsd of the xml output you are trying to create.
Either way, dropping your data into POCO style classes and serializing to XML is a lot better than trying to use the XmlWriter directly.
I've 2 questions:
First, I've a dataset with 5 tables. I've made the relationships of tables and generating an XML from this dataset like this:
StreamWriter xmlDoc = new StreamWriter("myxml.xml", false);
ds.WriteXml(xmlDoc);
xmlDoc.Close();
Some of the fields in each table in dataset are primary keys and I dont want to show them in XML. If I exclude them from tables, I cant make relationships. Can anybody give me some idea that how to write dataset to XML "droping" the key fields (columns in datatables)? For example, here is the XML generating at the moment:
<?xml version="1.0"?>
<o>
<sp spname="SP1" spid="8">
<event spid="8" eventname="Event1" eventId="482">
<bm bmname="BM1" bmid="2" bmeid="826" eventid="482">
<att bmeid="826" val="3.00" attname="Att1" atttype="Type1" attid="23172"/>
<att bmeid="826" val="3.50" attname="Att2" bettype="Type1" attid="23173"/>
</bm>
</event>
</sp>
</o>
but I want this XML to be generated like this (all id attributes should be "dropped" as all ids are for relationships and should not be added in XML):
<?xml version="1.0"?>
<o>
<sp spname="SP1">
<event eventname="Event1">
<bm bmname="BM1" bmid="2">
<att val="3.00" attname="Att1" atttype="Type1" />
<att val="3.50" attname="Att2" bettype="Type1" />
</bm>
</event>
</sp>
</o>
And now 2nd question:
I've given name to my dataset as "o" so its generating the xml as you can see above. I want to add some attributes to <o> node like current datetime. I mean I want <o> node to be genrated as <o generatedDate="09/13/2011" generatedTime="03:45 PM">. How can I achieve it?
Thanks,
You can hide the column to exclude it from the XML-File:
dataSet.Tables["TableName"].Columns["ColumnName"].ColumnMapping = MappingType.Hidden;
One option is to use LINQ to XML to alter the document. Another option would be to pass the XML into an XSLT transformer, which can parse the XML and output the desired results.
Transforming a DataSet using XSLT:
DataTable table = new DataTable();
System.IO.StringWriter writer = new System.IO.StringWriter();
//notice that we're ignoring the schema so we get clean XML back
//you can change the write mode as needed to get your result
table.WriteXml(writer, XmlWriteMode.IgnoreSchema, false);
string dataTableXml = writer.ToString();
As for displaying it in a readable format, I would suggest passing the XML into an XSL transformer, which you can then use to parse the XML and manipulate the output as needed.
Applying an XSLT Transform to a DataSet
http://msdn.microsoft.com/en-us/library/8fd7xytc%28v=vs.71%29.aspx#Y289
Here's a simple example I created to explain how you would use the XSL transformer. I haven't tested it, but it should be pretty close:
DataSet ds = new DataSet();
StringBuilder sbXslOutput = new StringBuilder();
using (XmlWriter xslWriter = XmlWriter.Create(sbXslOutput))
{
XslCompiledTransform transformer = new XslCompiledTransform();
transformer.Load("transformer.xsl");
XsltArgumentList args = new XsltArgumentList();
transformer.Transform(new XmlDataDocument(ds), args, xslWriter);
}
string dataSetHtml = sbXslOutput.ToString();
Formatting XML as HTML using XSLT
Here's an example of using XSLT to transform XML into an HTML table. It should be fairly easy to adopt so you can use it with your serialized DataSet.
Let's say this is your DataSet, serialized to XML:
<RecentMatter>
<UserLogin>PSLTP6\RJK</UserLogin>
<MatterNumber>99999-2302</MatterNumber>
<ClientName>Test Matters</ClientName>
<MatterName>DP Test Matter</MatterName>
<ClientCode>99999</ClientCode>
<OfficeCode/>
<OfficeName/>
<Billable>true</Billable>
<ReferenceId/>
<LastUsed>2011-08-23T23:40:24.13+01:00</LastUsed>
</RecentMatter>
<RecentMatter>
<UserLogin>PSLTP6\RJK</UserLogin>
<MatterNumber>999991.0002</MatterNumber>
<ClientName>Lathe 1</ClientName>
<MatterName>LW Test 2</MatterName>
<ClientCode/>
<OfficeCode/>
<OfficeName/>
<Billable>true</Billable>
<ReferenceId/>
<LastUsed>2011-07-12T16:57:27.173+01:00</LastUsed>
</RecentMatter>
<RecentMatter>
<UserLogin>PSLTP6\RJK</UserLogin>
<MatterNumber>999991-0001</MatterNumber>
<ClientName>Lathe 1</ClientName>
<MatterName>LW Test 1</MatterName>
<ClientCode/>
<OfficeCode/>
<OfficeName/>
<Billable>false</Billable>
<ReferenceId/>
<LastUsed>2011-07-12T01:59:06.887+01:00</LastUsed>
</RecentMatter>
</NewDataSet>
Here's an XSLT script that transforms the DataSet to HTML:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<table border="1">
<tr>
<th>User Login</th>
<th>Matter Number</th>
...
</tr>
<xsl:for-each select="NewDataSet/RecentMatter">
<tr>
<td>
<xsl:value-of select="UserLogin"/>
</td>
<td>
<xsl:value-of select="MatterNumber"/>
</td>
...
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
I would suggest after generating the XML, use LINQ to XML to filter out / add attribute to desired nodes. This filtering and adding attribute is a separate step then generating the XML from data set and should be handled after the XML is generated from data set as that would lead to better design.