I have a server that returns large amounts of comma separated data in an http response. I need to import this data into excel.
I have this working by passing the contents to a temp file and then reading the temp file as a csv, but this process seems inefficient. The query tables can read directly from the http response, but it puts each line of data into a single cell, rather than separating into one cell per comma.
Is it possible to read comma separated data from an http response directly into excel from a C# excel add-in?
Thanks!
public static void URLtoCSV(string URL, Excel.Worksheet destinationSheet, Excel.Range destinationRange, int[] columnDataTypes, bool autoFitColumns)
{
destinationSheet.QueryTables.Add(
"URL;" + URL,
destinationRange, Type.Missing);
destinationSheet.QueryTables[1].Name = URL;
destinationSheet.QueryTables[1].FieldNames = true;
destinationSheet.QueryTables[1].RowNumbers = false;
destinationSheet.QueryTables[1].FillAdjacentFormulas = false;
destinationSheet.QueryTables[1].PreserveFormatting = true;
destinationSheet.QueryTables[1].RefreshOnFileOpen = false;
destinationSheet.QueryTables[1].RefreshStyle = XlCellInsertionMode.xlInsertDeleteCells;
destinationSheet.QueryTables[1].SavePassword = false;
destinationSheet.QueryTables[1].SaveData = true;
destinationSheet.QueryTables[1].AdjustColumnWidth = true;
destinationSheet.QueryTables[1].RefreshPeriod = 0;
destinationSheet.QueryTables[1].Refresh(false);
if (autoFitColumns == true)
destinationSheet.QueryTables[1].Destination.EntireColumn.AutoFit();
}
The easier solution than the one you reference is to use the type of "TEXT" instead of URL. TEXT supports all CSV imports, including from HTTP sources. URL appears to be designed to handle screen scraping more than anything else.
e.g. in your case:
destinationSheet.QueryTables.Add("URL;" + URL,
becomes
destinationSheet.QueryTables.Add("TEXT;" + URL,
And for those stumbling upon this post asking the same question but with VB scripting in Excel, the complete solution would look like:
' Load new data from web
With ActiveSheet.QueryTables.Add(Connection:="TEXT;http://yourdomain.com/csv.php", Destination:=Range("$A$1"))
.TextFileCommaDelimiter = True
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlOverwriteCells
.SavePassword = False
.SaveData = False
.AdjustColumnWidth = True
.Refresh BackgroundQuery:=False
End With
Related
I am working with Google Sheet API. I am facing problem to read cell Note.
As below image, I am able to reading cell value i.e. "Ajay Gangwar", but not able to read cell note i.e. "Senior Software Engineer".
Below code working fine to read data from Google Sheet:
private static void readGoogleSheetNote(SheetsService sheetsService)
{
string spreadsheetId = "1FvPaJVu5z_Vml8eIqPK7q2WOWosOH-llL4p3FItg6Zo";
string range = "Sheet1";
SpreadsheetsResource.ValuesResource.GetRequest.ValueRenderOptionEnum valueRenderOption = (SpreadsheetsResource.ValuesResource.GetRequest.ValueRenderOptionEnum)0;
SpreadsheetsResource.ValuesResource.GetRequest.DateTimeRenderOptionEnum dateTimeRenderOption = (SpreadsheetsResource.ValuesResource.GetRequest.DateTimeRenderOptionEnum)0;
SpreadsheetsResource.ValuesResource.GetRequest getRequest = sheetsService.Spreadsheets.Values.Get(spreadsheetId, range);
getRequest.ValueRenderOption = valueRenderOption;
getRequest.DateTimeRenderOption = dateTimeRenderOption;
Google.Apis.Sheets.v4.Data.ValueRange response = getRequest.Execute();
Console.WriteLine(JsonConvert.SerializeObject(response));
Console.ReadKey();
}
The output of the above code is:
You have to use the Method: spreadsheets.get to get the cell notes, as seen on the Overview of Cells from this resource.
Using the following script you will get the data from the A4 cell. Inside the response there is the notes field:
String spreadsheetId = "SPREADSHEET ID";
String range = "Sheet1!A4";
bool includeGridData = true;
SpreadsheetsResource.GetRequest request = service.Spreadsheets.Get(spreadsheetId);
request.Ranges = range;
request.IncludeGridData = includeGridData;
Data.Spreadsheet response = request.Execute();
Console.WriteLine(JsonConvert.SerializeObject(response.Sheets));
The following code finds instances of the word "Family" in a Word document. It selects and deletes the instances. The code works fine, but I want to find all instances of only highlighted words.
public void FindHighlightedText()
{
const string filePath = "D:\\COM16_Duke Energy.doc";
var word = new Microsoft.Office.Interop.Word.Application {Visible = true};
var doc = word.Documents.Open(filePath);
var range = doc.Range();
range.Find.ClearFormatting();
range.Find.Text = "Family";
while (range.Find.Execute())
{
range.Select();
range.Delete();
}
doc.Close();
word.Quit(true, Type.Missing, Type.Missing);
}
Set the Find.Highlight property to true.
Interop uses the same objects and methods that are available to VBA macros. You can find the actions, properties you need to perform a task by recording a macro with those steps and inspecting it.
Often, but not always, the properties match the UI. If something is a property in the general Find box, it's probably a property in the Find interface as well.
For example, searching only for highlighted words produced this macro :
Selection.Find.ClearFormatting
Selection.Find.Highlight = True
With Selection.Find
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Which can be translated to :
range.Find.ClearFormatting();
range.Find.Highlight=1;
...
while(range.Find.Execute())
{
...
}
I've been trying to modify an Excel file called "Hoja de Resultados" adding three different variables each time (Puntuacion = Score, Fecha = Date, Hora = Time) inside of Visual Studio (C#). The excel sheet is linked to a DataGridView window which updates everytime the values are changed. The problem is, when there are less than 3 rows on the excel sheet, the program stops modifying the XLSX and sometimes it throws a seemingly random exception on "Program.cs".
string Direccion = "G:\\Archivos\\ProgramaciĆ³n\\Visual Basic\\UVG\\Microcontroladores - Proyecto Final ComunicaciĆ³n Serial\\Hoja de Resultados.xlsx";
Microsoft.Office.Interop.Excel.Application ExcelApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook Hoja = ExcelApp.Workbooks.Open(Direccion);
Microsoft.Office.Interop.Excel.Worksheet HojaActiva = ExcelApp.ActiveSheet as Microsoft.Office.Interop.Excel.Worksheet;
Excel.Range Rango = HojaActiva.UsedRange;
int Posicion = Rango.Rows.Count;
int NuevaPosicion = Posicion + 1;
HojaActiva.Cells[NuevaPosicion, 1] = Puntuacion;
HojaActiva.Cells[NuevaPosicion, 2] = Fecha;
HojaActiva.Cells[NuevaPosicion, 3] = Hora;
Hoja.Saved = true;
ExcelApp.DisplayAlerts = false;
ExcelApp.ScreenUpdating = false;
ExcelApp.Visible = false;
ExcelApp.UserControl = false;
ExcelApp.Interactive = false;
Hoja.Close(true, Type.Missing, Type.Missing);
Marshal.ReleaseComObject(Hoja);
Marshal.ReleaseComObject(HojaActiva);
ExcelApp.Quit();
Sorry if it's partially in Spanish. But for some guidance:
Hoja = Workbook
HojaActiva = ActiveWorkbook
The reason that your Excel file is not updating is because you're not saving it anywhere in code. To solve your saving problem,
Change this line:
Hoja.Saved = true;
To
Hoja.Save();
When you write Hoja.Saved = true;, it tells Excel that there are no changes to be saved, whether that is the case or not, and that it can safely exit. Thus it does not actually save anything. You have to call the Save() method explicitly.
Another possible issue in your code is if the active range does not begin at the very top. The line int NuevaPosicion = Posicion + 1; assumes that your input starts on row one, which may not be the case. I would recommend changing that line to this:
//This way it doesn't matter where the range starts.
// Rows.Row returns the row on which the active range begins.
int NuevaPosicion = Posicion + Rango.Rows.Row;
Now new data will always be appended to the end of the sheet.
Other than the two points above, I cannot replicate your problem with less than 3 rows on the excel sheet, the code you posted seems to run with no issues under all conditions I could think of. Try making the change above and see if that solves your other issues. If not, please update your question to describe the seemingly random exception on "Program.cs" a bit more explicitly.
I have been working successfully with the C# OpenXml SDK (Unofficial Microsoft Package 2.5 from NuGet) for some time now, but have recently noticed that the following line of code returns different results depending on what mood Microsoft Word appears to be in when the file gets saved:
var fields = document.Descendants<FieldCode>();
From what I can tell, when creating the document in the first place (using Word 2013 on Windows 8.1) if you use the Insert->QuickParts->Field and choose MergeField from the Field names left hand pane, and then provide a Field name in the field properties and click OK then the field code is correctly saved in the document as I would expect.
Then when using the aforementioned line of code I will receive a field code count of 1 field. If I subsequently edit this document (and even leave this field well alone) the subsequent saving could mean that this field code no longer is returned in my query.
Another case of the same curiousness is when I see the FieldCode nodes split across multiple items. So rather than seeing say:
" MERGEFIELD Author \\* MERGEFORMAT "
As the node name, I will see:
" MERGEFIELD Aut"
"hor \\* MERGEFORMAT"
Split as two FieldCode node values. I have no idea why this would be the case, but it certainly makes my ability to match nodes that much more exciting. Is this expected behaviour? A known bug? I don't really want to have to crack open the raw xml and edit this document to work until I understand what is going on. Many thanks all.
I came across this very problem myself, and found a solution that exists within OpenXML: a utility class called MarkupSimplifier which is part of the PowerTools for Open XML project. Using this class solved all the problems I was having that you describe.
The full article is located here.
Here are some pertinent exercepts :
Perhaps the most useful simplification that this performs is to merge adjacent runs with identical formatting.
It goes on to say:
Open XML applications, including Word, can arbitrarily split runs as necessary. If you, for instance, add a comment to a document, runs will be split at the location of the start and end of the comment. After MarkupSimplifier removes comments, it can merge runs, resulting in simpler markup.
An example of the utility class in use is:
SimplifyMarkupSettings settings = new SimplifyMarkupSettings
{
RemoveComments = true,
RemoveContentControls = true,
RemoveEndAndFootNotes = true,
RemoveFieldCodes = false,
RemoveLastRenderedPageBreak = true,
RemovePermissions = true,
RemoveProof = true,
RemoveRsidInfo = true,
RemoveSmartTags = true,
RemoveSoftHyphens = true,
ReplaceTabsWithSpaces = true,
};
MarkupSimplifier.SimplifyMarkup(wordDoc, settings);
I have used this many times with Word 2010 documents using VS2015 .Net Framework 4.5.2 and it has made my life much, much easier.
Update:
I have revisited this code and have found it clears upon runs on MERGEFIELDS but not IF FIELDS that reference mergefields e.g.
{if {MERGEFIELD When39} = "Y???" "Y" "N" }
I have no idea why this might be so, and examination of the underlying XML offers no hints.
Word will often split text runs with into multiple text runs for no reason I've ever understood. When searching, comparing, tidying etc. We preprocess the body with method which combines multiple runs into a single text run.
/// <summary>
/// Combines the identical runs.
/// </summary>
/// <param name="body">The body.</param>
public static void CombineIdenticalRuns(W.Body body)
{
List<W.Run> runsToRemove = new List<W.Run>();
foreach (W.Paragraph para in body.Descendants<W.Paragraph>())
{
List<W.Run> runs = para.Elements<W.Run>().ToList();
for (int i = runs.Count - 2; i >= 0; i--)
{
W.Text text1 = runs[i].GetFirstChild<W.Text>();
W.Text text2 = runs[i + 1].GetFirstChild<W.Text>();
if (text1 != null && text2 != null)
{
string rPr1 = "";
string rPr2 = "";
if (runs[i].RunProperties != null) rPr1 = runs[i].RunProperties.OuterXml;
if (runs[i + 1].RunProperties != null) rPr2 = runs[i + 1].RunProperties.OuterXml;
if (rPr1 == rPr2)
{
text1.Text += text2.Text;
runsToRemove.Add(runs[i + 1]);
}
}
}
}
foreach (W.Run run in runsToRemove)
{
run.Remove();
}
}
I tried to simplify the document with Powertools but the result was a corrupted word file. I make this routine for simplify only fieldcodes that has specifics names, works in all parts on the docs (maindocumentpart, headers and footers):
internal static void SimplifyFieldCodes(WordprocessingDocument document)
{
var masks = new string[] { Constants.VAR_MASK, Constants.INP_MASK, Constants.TBL_MASK, Constants.IMG_MASK, Constants.GRF_MASK };
SimplifyFieldCodesInElement(document.MainDocumentPart.RootElement, masks);
foreach (var headerPart in document.MainDocumentPart.HeaderParts)
{
SimplifyFieldCodesInElement(headerPart.Header, masks);
}
foreach (var footerPart in document.MainDocumentPart.FooterParts)
{
SimplifyFieldCodesInElement(footerPart.Footer, masks);
}
}
internal static void SimplifyFieldCodesInElement(OpenXmlElement element, string[] regexpMasks)
{
foreach (var run in element.Descendants<Run>()
.Select(item => (Run)item)
.ToList())
{
var fieldChar = run.Descendants<FieldChar>().FirstOrDefault();
if (fieldChar != null && fieldChar.FieldCharType == FieldCharValues.Begin)
{
string fieldContent = "";
List<Run> runsInFieldCode = new List<Run>();
var currentRun = run.NextSibling();
while ((currentRun is Run) && currentRun.Descendants<FieldCode>().FirstOrDefault() != null)
{
var currentRunFieldCode = currentRun.Descendants<FieldCode>().FirstOrDefault();
fieldContent += currentRunFieldCode.InnerText;
runsInFieldCode.Add((Run)currentRun);
currentRun = currentRun.NextSibling();
}
// If there is more than one Run for the FieldCode, and is one we must change, set the complete text in the first Run and remove the rest
if (runsInFieldCode.Count > 1)
{
// Check fielcode to know it's one that we must simplify (for not to change TOC, PAGEREF, etc.)
bool applyTransform = false;
foreach (string regexpMask in regexpMasks)
{
Regex regex = new Regex(regexpMask);
Match match = regex.Match(fieldContent);
if (match.Success)
{
applyTransform = true;
break;
}
}
if (applyTransform)
{
var currentRunFieldCode = runsInFieldCode[0].Descendants<FieldCode>().FirstOrDefault();
currentRunFieldCode.Text = fieldContent;
runsInFieldCode.RemoveAt(0);
foreach (Run runToRemove in runsInFieldCode)
{
runToRemove.Remove();
}
}
}
}
}
}
Hope this helps!!!
I'm writing a C# program to run QTP.
Now my program can trigger QTP automatically and send the result to my mailbox. But this result is HTML, i find that QTP can export a PDF result.
so, here is my code.
qtpAutoReport = qtpApp.Options.Run.AutoExportReportConfig;
qtpAutoReport.AutoExportResults = true;
qtpAutoReport.StepDetailsReport = true;
qtpAutoReport.DataTableReport = false;
qtpAutoReport.LogTrackingReport = false;
qtpAutoReport.ScreenRecorderReport = false;
qtpAutoReport.SystemMonitorReport = false;
qtpAutoReport.StepDetailsReportFormat = "Short";
qtpAutoReport.ExportLocation = AutoExportPath;
qtpAutoReport.ExportForFailedRunsOnly = false;
qtpAutoReport.StepDetailsReportType = "PDF";
When i use this code qtpAutoReport.StepDetailsReportType = "HTML";
My program can run successfully, and i can find this HTML file on my disk.
But, when i use this code qtpAutoReport.StepDetailsReportType = "PDF";
After QTP test is over, i can't any file on my disk.
So my question is why QTP can't export result when i set StepDetailsReportType as "PDF"?
There does seem to be an issue with UFT, I found a method that works for GUI tests(vbscript), give it a try with Service Test (c#).
All options are the same as your example, with one addition:
uftObject.Options.Run.ViewResults = True
This tells UFT that you want to view the results after completion. Without this flag I get no PDF result, with it the file is waiting at the export path.
Option Explicit
Dim uftObject, qtResultsOpt
Set uftObject=CreateObject("Quicktest.application")
uftObject.Launch
uftObject.Visible = True
Set qtResultsOpt = uftObject.Options.Run.AutoExportReportConfig
Dim AutoExportPath
AutoExportPath = "C:\Users\paxic\Desktop\stackoverflow\results"
qtResultsOpt.AutoExportResults = true
qtResultsOpt.StepDetailsReport = true
qtResultsOpt.DataTableReport = false
qtResultsOpt.LogTrackingReport = false
qtResultsOpt.ScreenRecorderReport = false
qtResultsOpt.SystemMonitorReport = false
qtResultsOpt.StepDetailsReportFormat = "Short"
qtResultsOpt.ExportLocation = AutoExportPath
qtResultsOpt.ExportForFailedRunsOnly = false
qtResultsOpt.StepDetailsReportType = "PDF"
uftObject.Open "C:\Users\JMorley\Desktop\stackoverflow\ExampleOne"
qtResultsOpt.AutoExportResults = True
uftObject.Options.Run.ViewResults = True
uftObject.Test.Run