I am using the PDF clown library to edit a pre-existing PDF (mass autofilling them based on user input) and i'm having trouble changing the form fields (specifically the textfields) value, when attempting to run the code below i will be given this error which is highlighted on the code sample below
" System.InvalidCastException: 'Unable to cast object of type 'org.pdfclown.objects.PdfName' to type 'org.pdfclown.objects.IPdfNumber'.'"
the block of code im having trouble with is a loop that runs through each field and attempts to locate the field matching the name and then altering that fields Value to match the hardcoded string
using org.pdfclown.documents;
using org.pdfclown.documents.contents.composition;
using org.pdfclown.documents.contents.entities;
using org.pdfclown.documents.contents.fonts;
using org.pdfclown.documents.contents.xObjects;
using org.pdfclown.documents.interaction.annotations;
using org.pdfclown.documents.interaction.forms;
using org.pdfclown.documents.files;
using org.pdfclown.objects;
using org.pdfclown.files;
using files = org.pdfclown.files;
using System;
using System.Collections.Generic;
using System.Drawing;
namespace PDFedit
{
class PDFLoader
{
public static void load (string path )
{
string filepath = path;
File file = new File(filepath);
Document document = file.Document;
Form form = document.Form;
Fields fields = form.Fields;
string value = "william";
foreach (Field field in form.Fields.Values)
{
if (field.Name == "Testtext")
{
string typeName = field.GetType().name;
field.value = "data to be written into the field" // this is the line that throws
the error
Console.WriteLine(" Type: " + typeName);
Console.WriteLine(" Value: " + field.Value);
Console.WriteLine(" Data: " + field.BaseDataObject.ToString());
}
};
file.Save();
}
}
}
Apologies if i've committed any fauxpas in asking a question, this is my first post and i'm new to programming outside of a tutorial environment.
Related
using System.IO;
using System.Collections.Generic;
using OfficeOpenXml;
namespace Project
{
public class CreateExcel
{
public static void GenerateExcel(List<string> headerList, List<string> dataList, FileInfo filePath)
{
using (ExcelPackage excel = new ExcelPackage())
{
excel.Workbook.Worksheets.Add("Worksheet1");
// Determine the header range (e.g. A1:D1)
string headerRange = "A1:" + Char.ConvertFromUtf32(headerList.Count + 64) + "1";
// Target a worksheet
var worksheet = excel.Workbook.Worksheets["Worksheet1"];
// Popular header row data
worksheet.Cells[headerRange].LoadFromCollection(headerList);
worksheet.Cells[2, 1].LoadFromCollection(dataList, false);
excel.SaveAs(filePath);
}
}
}
I would like to create .xlsx file with this function, but the headerRange get "A1:^1" value (when I use my headerList, which has 30 elements), and of course I get this error: System.Exception: 'Invalid Address format ^1'
.
How to set correctly the headerRange?
Use LoadFromArrays instead :
var values=new List<object[]> {
headerList.ToArray(),
dataList.ToArray()
};
worksheet.Cells["A1"].LoadFromArrays(values);
LoadFromCollection loads data from a strongly typed collection using reflection to create a different column for each property
What i want to do here was getting an string input from the user and if that string input is in the array i want to delete it from the file (all the items in the array is actual files in my computer that got scanned at the start of the program and become one array) is there a way to do that without foreach?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.IO;
using System.Threading;
string typed = null;
string loc = AppDomain.CurrentDomain.BaseDirectory;
if (!Directory.Exists(loc + #"\shortcuts"))
{
Directory.CreateDirectory(loc + #"\shortcuts");
}
string[] directory = Directory.GetFiles(loc + #"\shortcuts");
foreach (var filed in directory)
{
File.Move(filed, filed.ToLowerInvariant());
}
string[] file = Directory.GetFiles(loc + #"\shortcuts").Select(System.IO.Path.GetFileNameWithoutExtension).ToArray();
foreach (string dir in directory)
{
}
if (typed == "exit") System.Environment.Exit(0);
//other ifs here
else if (typed == "rem")
{
//Console.WriteLine("\nNot available at the moment\n");
////add this command
Console.WriteLine("\nWhich program entry do you wish to erase?\n");
typed = Console.ReadLine().ToLower();
if (file.Any(typed.Contains))
{
File.Delete(file.Contains(typed)); //this is the broken part and i don't know how i can get the stings from there
Console.WriteLine("hi");
}
else Console.WriteLine("\n" + typed + " is not in your registered programs list.\n");
}
Expected result was getting rid of the typed program in the folder and actual results was just an error code.
You are storing only the file name in the array, not its complete path or extension. You need to change this, and allow it to store FileName with extension.
string[] file = Directory.GetFiles(loc + #"\shortcuts").Select(System.IO.Path.GetFileName).ToArray();
and then, you need to change the If condition as follows.
if (file.Contains(typed))
{
File.Delete(Path.Combine(loc + #"\shortcuts",typed));
Console.WriteLine("hi");
}
In this Scenario, user would need to input the file name with extension.
If you want the User to input only the filename(without extension, as in your code), then, you could run into a situation where there could be two files with different extension.
"test.jpg"
"test.bmp"
Update
Based on your comment that you cannot store extensions, please find the updated code below. In this scenario, you do not need to change the array. Since you are only storing lnk files, you can append the extension to the file name to complete the path during Path.Combine.
if (file.Contains(typed))
{
File.Delete(Path.Combine(loc , #"shortcuts",$"{typed}.lnk"));
Console.WriteLine("hi");
}
In an effort to minimize time spent on reading error logs, I have created the following small plugin that will parse relevant information contained within Elmah error logs, and eventually produce an Excel spreadsheet. For the time being I am using a WriteLine to test. The issue I am facing is that inside the second foreach loop I am seeing a null reference exception in each of the node.attribute items. The expected outcome of this code is to produce a list of "attribute" values from within the <error> tag of each of the XML documents.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
namespace ExcelSortingAutomation
{
public class Program
{
public static void Main(string[] args)
{
DirectoryInfo Exceptions = new DirectoryInfo("C:\\ErrorsMay2017");
FileInfo[] ExceptionFiles = Exceptions.GetFiles("*.xml");
foreach (var exception in ExceptionFiles)
{
string xml = "<error></error>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
foreach (XmlNode node in doc.SelectNodes("//error"))
{
string errorId = node.Attributes["errorId"].Value;
string type = node.Attributes["type"].Value;
string message = node.Attributes["message"].Value;
string time = node.Attributes["time"].Value;
Console.WriteLine("{0} - {1} - {2} = {3}", errorId, type, message, time);
}
}
}
}
}
My question is, Why would the logs, which should be pulled and parsed by this point, not be receiving the Attribute values?
Edit 1: upon closer inspection, the XmlNode Node value is returning without "HasAttributes"
The line string xml = "<error></error>"; should be replace with string xml = File.ReadAllText(exception.FullName));
I am writing a C# class to use for generating email lists to use when a process either succeeds or fails. In running through XmlReader examples from the web, I found that validating the Read() is tougher than it looks.
I can use string.IsNullOrEmpty(x) to test for a null value or and empty node, but it will still blow by that test showing a "\n " in the tooltip for x. Testing for "\n ", '\n ', '\n'. "\n" or char(13) all fail. If I use x.Contains((char)13), it always find it and goes into the code trying to build the email address list. So far, it either always fails or always succeeds.
I found some old posts on stackoverflow where it seemed like the question was the same, but my results don't match with the answers. My environment is Windows 8.1 running Visual Studio 2013 with .Net Framework 4.51. The example from the web I was trying to make work before using the solution in my class is at Microsoft.com
My conversion is below:
using System;
using System.Text;
using System.Linq;
using System.Xml;
using System.Xml.Schema;
using System.IO;
using System.Collections.Generic;
namespace XMLDemo
{
public class project
{
public static void Main()
{
string uri = #"C:\\events\items.xml";
string process_state = "Item";
string emails = StreamEmailAddress(uri, process_state);
}
private static string StreamEmailAddress(string uri, string process_state)
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
XmlReader reader = XmlReader.Create(uri, settings);
string returnValue = "";
reader.MoveToContent();
while (reader.Read())
{
string x = reader.Value;
if ((string.IsNullOrEmpty(x) == false) && (x.Contains((char)13)))
{
returnValue = returnValue + x + "; ";
}
}
Console.WriteLine("Made it to the end: " + returnValue);
return returnValue;
}
}
}
You should use string.IsNullOrWhiteSpace
SOLVED: After futzing with it all day, I looked at it with slightly fresher eyes after posting and saw the blatant error. I was using the incorrect function and trying to resolve line feeds by myself. By replacing IsNullOrEmpty(x) with IsNullOrWhiteSpace(x), I got the string of data as expected. Doing the code with email addresses will be easy now.
For one of my projects in college I had to create a test as a Word document and add some ActiveX forms in it to be completed by another person. After this I had to programmatically extract the answers from it and put a grade on the test.
I used OpenXML SDK for processing the document, but it gave me headaches because I couldn't find a way to get the ActiveX values.
So what was the solution?
After searching the Internet and a bit of sniffing on the document I have found that the ActiveX control data can be found in a document part specified by the control ID. Determining the type of control is a bit tricky because I didn't find any documentation about this. Apparently you must get the "classid" attribute from a control and try to match it to the classids you know. Below is the code for determining the values for three types of controls. The rest of the ids are marked as not known and you can match them intuitively to the ones you added in the document.
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Xml;
using System.IO;
using System.Text;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXMLTest
{
class Program
{
const string textBoxId = "{8BD21D10-EC42-11CE-9E0D-00AA006002F3}";
const string radioButtonId = "{8BD21D50-EC42-11CE-9E0D-00AA006002F3}";
const string checkBoxId = "{8BD21D40-EC42-11CE-9E0D-00AA006002F3}";
static void Main(string[] args)
{
string fileName = #"C:\Users\Andy\Desktop\test_l1demo.docx";
using (WordprocessingDocument doc = WordprocessingDocument.Open(fileName, false))
{
foreach (Control control in doc.MainDocumentPart.Document.Body.Descendants())
{
Console.WriteLine();
Console.WriteLine("Control {0}:", control.Name);
Console.WriteLine("Id: {0}", control.Id);
displayControlDetails(doc, control.Id);
}
}
Console.Read();
}
private static void displayControlDetails(WordprocessingDocument doc, StringValue controlId)
{
string classId, type, value;
OpenXmlPart part = doc.MainDocumentPart.GetPartById(controlId);
OpenXmlReader reader = OpenXmlReader.Create(part.GetStream());
reader.Read();
OpenXmlElement controlDetails = reader.LoadCurrentElement();
classId = controlDetails.GetAttribute("classid", controlDetails.NamespaceUri).Value;
switch (classId)
{
case textBoxId:
type = "TextBox";
break;
case radioButtonId:
type = "Radio Button";
break;
case checkBoxId:
type = "CheckBox";
break;
default:
type = "Not known";
break;
}
value = "No value attribute"; //displays this if there is no "value" attribute found
foreach (OpenXmlElement child in controlDetails.Elements())
{
if (child.GetAttribute("name", controlDetails.NamespaceUri).Value == "Value")
{
//we've found the value typed by the user in this control
value = child.GetAttribute("value", controlDetails.NamespaceUri).Value;
}
}
reader.Close();
Console.WriteLine("Class id: {0}", classId);
Console.WriteLine("Control type: {0}", type);
Console.WriteLine("Control value: {0}", value);
}
}
}