Reading PDF Forms Data into SharePoint Lists - sharepoint

I have an application where customers fill out a PDF form and then post it to a sharepoint library. Once the document is posted, we want to kick of an event handler to extract the user data from the form and post it into one or more sharepoint lists.
Any ideas on how I get started- I'm a novice with PDF forms but have a good understanding of SharePoint development.

Take a look at www.pdfsharepoint.com. Their product allows filling in Pdf forms and submitting them in to SharePoint. Fields can be mapped to SharePoint columns.
Dmitry

You can write a custom handler that catches a PDF Form submit as explained here (includes sample code).
Alternatively you can use a workflow that is triggered when a PDF Form is saved and extract the data from the form using a third party library.
If you prefer to use SharePoint Designer workflows then you can embed your .net code directly into the workflow using a product such as the Workflow Power Pack. (Disclaimer, I worked on this product and it is fab ;-).
You probably have a good reason to use PDF Forms, but you could also consider using InfoPath or even MS-Word to fill out your forms. It is easy to extract Word and InfoPath data from SharePoint and if you wish you can convert the documents to PDF as well.

If you can use PDF form submit action then you can have the form submit the data directly to the SharePoint list. To do this, you will need to create a custom http handler and save it to _Layouts folder with ".ashx" extension.
In PDF form, set the submit action to submit the data in XML and point it to the URL of the http handler.
Here is example code of the handler;
<%# Assembly Name="Microsoft.SharePoint,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" %>
<%# WebHandler Language="C#" Class="SP_PDFSubmitHandler" %>
using System;
using System.Web;
using Microsoft.SharePoint;
using System.Xml;
public class SP_PDFSubmitHandler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
SPSite site = SPContext.Current.Site;
SPWeb web = site.OpenWeb();
try
{
string rawXML = "";
XmlTextReader reader = new XmlTextReader(context.Request.InputStream);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
string _xmlString = xmlDoc.InnerXml;
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
string _fileTime = DateTime.Now.ToFileTime().ToString();
byte[] docAsBytes = encoding.GetBytes(_xmlString);
//Insert Document
web.AllowUnsafeUpdates = true;
SPList list = web.Lists["Purchase Order"];
SPListItem item = list.Items.Add();
item["Title"] = "PurchaseOrder_" + _fileTime + ".xml";
item["Company Name"] = xmlDoc.GetElementsByTagName("txtOrderedByCompanyName").Item(0).InnerText;
item["Date"] = xmlDoc.GetElementsByTagName("dtmDate").Item(0).InnerText;
item["Order Total"] = xmlDoc.GetElementsByTagName("numGrandTotal").Item(0).InnerText;
item.Attachments.Add("PurchaseOrder_" + _fileTime + ".xml", docAsBytes);
item.Update();
//Redirect the browser to the Purchase Order list so we can see our submisison.
context.Response.Redirect("http://myserver/Lists/Purchase%20Order/AllItems.aspx");
}
catch (Exception ex)
{
context.Response.Write(ex.Message);
}
}
public bool IsReusable {
get {
return false;
}
}
}
Here is a great post which describes the process http://blogs.adobe.com/mtg/2009/03/submitting-data-from-an-pdf-form-to-ms-sharepoint.html
Here is the MSDN post about Handlers https://msdn.microsoft.com/en-us/library/bb457204.aspx

Related

Customizing upload file functionality in SharePoint picture library

Can anyone help me ,I want to customize upload functionality in which i want to validate the uploaded image type to the picture library
where can i set my script ?? Any one can advise ???
You might be Use ItemAdding. In ItemAdding Event Method just check extension of the Document before successfully uploaded to the Library.if unvalid document than through Error message
your code something like this :
protected string[] ValidExtensions = new string[] { "png", "jpeg", "gif"};
public override void ItemAdding(SPItemEventProperties properties)
{
string strFileExtension = Path.GetExtension(properties.AfterUrl);
bool isValidExtension = false;
string strValidFileTypes = string.Empty;
using (SPWeb web = properties.OpenWeb())
{
foreach (string strValidExt in ValidExtensions)
{
if (strFileExtension.ToLower().EndsWith(strValidExt.ToLower()))
{
isValidExtension = true;
}
strValidFileTypes += (string.IsNullOrEmpty(strValidFileTypes) ? "" : ", ") + strValidExt;
}
// Here i am going to check is this validate or not if not than redirect to the
//Error Message Page.
if (!isValidExtension)
{
properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
properties.RedirectUrl = properties.WebUrl + "/_layouts/error.aspx?ErrorText=" + "Only " + strValidFileTypes + " extenstions are allowed";
}
}
}
You could use SPItemEventReceiver for your library and add your logic into ItemUpdating() and ItemAdding() methods.
You can try creating a custom list template and replace the default NewForm.aspx and EditForm.aspx pages there. These custom form templates need not contain the same user controls and buttons as in the default picture library template. You could create a Silverlight web part with rich UI to upload images, e.g. The more you want to differ the more code you'll have to write...
An OOTB solution I can think of would be a workflow that you would force every new picture to run through but it would be quite an overkill for the end-user...
Of course, if you're able to validate by using just the meta-data in ItemAdding as the others suggest, it'd be a huge time-saver.
--- Ferda

Programmatically Edit Infopath Form Fields?

I have a form library in my share point site. Programmatically I need to fill some fields. Can I do that? If any one know please provide me some sample code. First I need to retrieve the infopath document and then I need to fill the fields.
What axel_c posted is pretty dang close. Here's some cleaned up and verified working code...
public static void ChangeFields()
{
//Open SharePoint site
using (SPSite site = new SPSite("http://<SharePoint_Site_URL>"))
{
using (SPWeb web = site.OpenWeb())
{
//Get handle for forms library
SPList formsLib = web.Lists["FormsLib"];
if (formsLib != null)
{
foreach (SPListItem item in formsLib.Items)
{
XmlDocument xml = new XmlDocument();
//Open XML file and load it into XML document
using (Stream s = item.File.OpenBinaryStream())
{
xml.Load(s);
}
//Do your stuff with xml here. This is just an example of setting a boolean field to false.
XmlNodeList nodes = xml.GetElementsByTagName("my:SomeBooleanField");
foreach (XmlNode node in nodes)
{
node.InnerText = "0";
}
//Get binary data for new XML
byte[] xmlData = System.Text.Encoding.UTF8.GetBytes(xml.OuterXml);
using (MemoryStream ms = new MemoryStream(xmlData))
{
//Write data to SharePoint XML file
item.File.SaveBinary(ms);
}
}
}
}
}
}
The Infopath document is just a regular XML file, the structure of which matches the data sources you defined in the Infopath form.
You just need to access the file via the SharePoint object model, modify it using standard methods (XmlDocument API) and then write it back to the SharePoint list. You must be careful to preserve the structure and insert valid data or you won't be able to open the form using Infopath.
You should really check out a book on SharePoint if you plan to do any serious development. Infopath is also a minefield.
Object model usage examples: here, here and here. The ridiculously incomplete MSDN reference documentation is here.
EDIT: here is some example code. I haven't done SharePoint for a while so I'm not sure this is 100% correct, but it should give you enough to get started:
// Open SharePoint site
using (SPSite site = new SPSite("http://<SharePoint_Site_URL>"))
{
using (SPWeb web = site.OpenWeb())
{
// Get handle for forms library
SPList formsLib = web.Lists["FormsLib"];
if (formsLib != null)
{
SPListItem itm = formsLib.Items["myform.xml"];
// Open xml and load it into XML document
using (Stream s = itm.File.OpenBinary ())
{
MemoryStream ms;
byte[] xmlData;
XmlDocument xml = new XmlDocument ();
xml.Load (s);
s.Close ();
// Do your stuff with xml here ...
// Get binary data for new XML
xmlData = System.Text.Encoding.UTF8.GetBytes (xml.DocumentElement.OuterXml);
ms = new MemoryStream (xmlData);
// Write data to sharepoint item
itm.File.SaveBinary (ms);
ms.Close ();
itm.Update ();
}
}
web.Close();
}
site.Close();
}
It depends a bit on your available tool set, skills and exact requirements.
There are 2 main ways of pre populating data inside an InfoPath form.
Export the relevant fields as part of the form's publishing process. The fields will then become columns on the Document / Forms library from where you can manipulate them either manually, via a Workflow or wherever your custom code is located.
Directly manipulate the form using code similar to what was provided by Axel_c previously. The big question here is: what will trigger this code? An event receiver on the Document Library, a SharePoint Designer Workflow, a Visual Studio workflow etc?
If you are trying to do this from a SharePoint Designer workflow then have a look at the Workflow Power Pack for SharePoint. It allows C# and VB code to be embedded directly into the workflow without the need for complex Visual Studio development. An example of how to query InfoPath data from a workflow can be found here. If you have some development skills you should be able to amend it to suit your needs.
I also recommend the site www.infopathdev.com, they have excellent and active forums. You will almost certainly find an answer to your question there.
Thanks for the sample code, #axel_c and #Jeff Burt
Below is just the same code from Jeff Burt modified for a file in Document set which I needed. If you don't already have the Document Set reference, you can check out this site on how to grab one:
http://howtosharepoint.blogspot.com/2010/12/programmatically-create-document-set.html
Also, the codes will open the .xml version of the infopath form and not the .xsn template version which you might run into.
Thanks again everyone...
private void ChangeFields(DocumentSet docSet)
{
string extension = "";
SPFolder documentsetFolder = docSet.Folder;
foreach (SPFile file in documentsetFolder.Files)
{
extension = Path.GetExtension(file.Name);
if (extension != ".xml") //check if it's a valid xml file
return;
XmlDocument xml = new XmlDocument();
//Open XML file and load it into XML document, needs to be .xml file not .xsn
using (Stream s = file.OpenBinaryStream())
{
xml.Load(s);
}
//Do your stuff with xml here. This is just an example of setting a boolean field to false.
XmlNodeList nodes = xml.GetElementsByTagName("my:fieldtagname");
foreach (XmlNode node in nodes)
{
node.InnerText = "xyz";
}
//Get binary data for new XML
byte[] xmlData = System.Text.Encoding.UTF8.GetBytes(xml.OuterXml);
using (MemoryStream ms = new MemoryStream(xmlData))
{
//Write data to SharePoint XML file
file.SaveBinary(ms);
}
}
}
I had this issue and resolved it with help from Jeff Burt / Axel_c's posts.
I was trying to use the XMLDocument.Save([stream]) and SPItem.File.SaveBinary([stream]) methods to write an updated InfoPath XML file back to a SharePoint library. It appears that XMLDocument.Save([stream]) writes the file back to SharePoint with the wrong encoding, regardless of what it says in the XML declaration.
When trying to open the updated InfoPath form I kept getting the error "a calculation in the form has not been completed..."
I've written these two functions to get and update and InfoPath form. Just manipulate the XML returned from ReadSPFiletoXMLdocument() in the usual way and send it back to your server using WriteXMLtoSPFile().
private System.Xml.XmlDocument ReadSPFiletoXMLdocument(SPListItem item)
{
//get SharePoint file XML
System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
try
{
using (System.IO.Stream xmlStream = item.File.OpenBinaryStream())
{
xDoc.Load(xmlStream);
}
}
catch (Exception ex)
{
//put your own error handling here
}
return xDoc;
}
private void WriteXMLtoSPFile(SPListItem item, XmlDocument xDoc)
{
byte[] xmlData = System.Text.Encoding.UTF8.GetBytes(xDoc.OuterXml);
try
{
using (System.IO.MemoryStream outStream = new System.IO.MemoryStream(xmlData))
{
item.File.SaveBinary(outStream);
}
}
catch (Exception ex)
{
//put your own error handling here
}
}

Sharepoint : Access denied when editing a page (because of page layout) or list item

I'm logged in as the System Account, so it's probably not a "real access denied"!
What I've done :
- A custom master page
- A custom page layout from a custom content type (with custom fields)
If I add a custom field (aka "content field" in the tools in SPD) in my page layout, I get an access denied when I try to edit a page that comes from that page layout.
So, for example, if I add in my page layout this line in a "asp:content" tag :
I get an access denied. If I remove it, everyting is fine. (the field "test" is a field that comes from the content type).
Any idea?
UPDATE
Well, I tried in a blank site and it worked fine, so there must be something wrong with my web application :(
UPDATE #2
Looks like this line in the master page gives me the access denied :
<SharePoint:DelegateControl runat="server" ControlId="PublishingConsole" Visible="false"
PrefixHtml="<tr><td colspan="0" id="mpdmconsole" class="s2i-consolemptablerow">"
SuffixHtml="</td></tr>"></SharePoint:DelegateControl>
UPDATE #3
I Found http://odole.wordpress.com/2009/01/30/access-denied-error-message-while-editing-properties-of-any-document-in-a-moss-document-library/
Looks like a similar issue. But our Sharepoint versions are with the latest updates. I'll try to use the code that's supposed to fix the lists and post another update.
** UPDATE #4**
OK... I tried the code that I found on the page above (see link) and it seems to fix the thing. I haven't tested the solution at 100% but so far, so good. Here's the code I made for a feature receiver (I used the code posted from the link above) :
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.Xml;
namespace MyWebsite.FixAccessDenied
{
class FixAccessDenied : SPFeatureReceiver
{
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
FixWebField(SPContext.Current.Web);
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
//throw new Exception("The method or operation is not implemented.");
}
public override void FeatureInstalled(SPFeatureReceiverProperties properties)
{
//throw new Exception("The method or operation is not implemented.");
}
public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
//throw new Exception("The method or operation is not implemented.");
}
static void FixWebField(SPWeb currentWeb)
{
string RenderXMLPattenAttribute = "RenderXMLUsingPattern";
SPSite site = new SPSite(currentWeb.Url);
SPWeb web = site.OpenWeb();
web.AllowUnsafeUpdates = true;
web.Update();
SPField f = web.Fields.GetFieldByInternalName("PermMask");
string s = f.SchemaXml;
Console.WriteLine("schemaXml before: " + s);
XmlDocument xd = new XmlDocument();
xd.LoadXml(s);
XmlElement xe = xd.DocumentElement;
if (xe.Attributes[RenderXMLPattenAttribute] == null)
{
XmlAttribute attr = xd.CreateAttribute(RenderXMLPattenAttribute);
attr.Value = "TRUE";
xe.Attributes.Append(attr);
}
string strXml = xe.OuterXml;
Console.WriteLine("schemaXml after: " + strXml);
f.SchemaXml = strXml;
foreach (SPWeb sites in site.AllWebs)
{
FixField(sites.Url);
}
}
static void FixField(string weburl)
{
string RenderXMLPattenAttribute = "RenderXMLUsingPattern";
SPSite site = new SPSite(weburl);
SPWeb web = site.OpenWeb();
web.AllowUnsafeUpdates = true;
web.Update();
System.Collections.Generic.IList<Guid> guidArrayList = new System.Collections.Generic.List<Guid>();
foreach (SPList list in web.Lists)
{
guidArrayList.Add(list.ID);
}
foreach (Guid guid in guidArrayList)
{
SPList list = web.Lists[guid];
SPField f = list.Fields.GetFieldByInternalName("PermMask");
string s = f.SchemaXml;
Console.WriteLine("schemaXml before: " + s);
XmlDocument xd = new XmlDocument();
xd.LoadXml(s);
XmlElement xe = xd.DocumentElement;
if (xe.Attributes[RenderXMLPattenAttribute] == null)
{
XmlAttribute attr = xd.CreateAttribute(RenderXMLPattenAttribute);
attr.Value = "TRUE";
xe.Attributes.Append(attr);
}
string strXml = xe.OuterXml;
Console.WriteLine("schemaXml after: " + strXml);
f.SchemaXml = strXml;
}
}
}
}
Just put that code as a Feature Receiver, and activate it at the root site, it should loop trough all the subsites and fix the lists.
SUMMARY
You get an ACCESS DENIED when editing a PAGE or an ITEM
You still get the error even if you're logged in as the Super Admin of the f****in world (sorry, I spent 3 days on that bug)
For me, it happened after an import from another site definition (a cmp file)
Actually, it's supposed to be a known bug and it's supposed to be fixed since February 2009, but it looks like it's not.
The code I posted above should fix the thing.
Try to publish your MasterPage and Page Layouts, this is the most common reason. Since the system account is godmode, it wont get that error.
In SharePoint Designer you cannot do the last step in the publishing workflow (Approval), so you:
SharePoint Designer:
CheckIn => Publish Major Version, hit the OK button or go to /_catalogs/masterpage on the site .
Then and use the Context Menu to Approve the MasterPage and Layouts.
Some ideas:
Check if any web parts in your custom Page Layout and Master Page are not registered as safe.
Did you define your own custom field type, like write a class which extends SPField? If so, are you using a custom Field Control? If you are, check if it is doing anything which may need elevated privileges.
Likewise, check for any edit mode panels containing web parts of web controls which might be trying to do something which needs elevated privileges.
See the code I've posted in the edit of the post. It fixed my problem.
The problem appears to be caused by an error in the stsadm -o export function in certain versions of SharePoint (I got it doing an export from a 2007 RTM MOSS server). Importing the bogus export file causes the "edit-denied-access" problem in all NEWLY-CREATED lists. The patches for later version from Microsoft fix stsadm -o export, but DO NOT FIX the broken lists; that requires a procedure like tinky05's.

Programmatically insert a List as a webpart in a webpart page in WSS 3.0

I tried searching on the net to programmatically insert a List as a webpart in a webpart page but was not lucky enough.
Any thoughts or ideas how i could Programmatically insert a List as a webpart in a webpart page
Many Thanks!
First add these using statements.
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebPartPages;
Then in your code
// First get the list
SPSite site = new SPSite("http://myserver");
SPWeb web = site.OpenWeb();
SPList list = web.Lists["MyCustomlist"];
// Create a webpart
ListViewWebPart wp = new ListViewWebPart();
wp.ZoneID = "Top"; // Replace this ith the correct zone on your page.
wp.ListName = list.ID.ToString("B").ToUpper();
wp.ViewGuid = list.DefaultView.ID.ToString("B").ToUpper();
// Get the web part collection
SPWebPartCollection coll =
web.GetWebPartCollection("default.aspx", // replace this with the correct page.
Storage.Shared);
// Add the web part
coll.Add(wp);
If you want to use a custom view, try playing with this:
SPView view = list.GetUncustomizedViewByBaseViewId(0);
wp.ListViewXml = view.HtmlSchemaXml;
Hope it helps,
W0ut
You need to perform two steps to add a web part to a page. First you have to create the list you want to show on the page. Therefore you can use the Add() method of the web site's list collection (SPListCollection).
To show the list on the web part page you have to add a ListViewWebPart to the web part page using the SPLimitedWebPartManager of the page.
To make this more re-usable as part of a feature receiver, you could pass in the splist and spview as part of a method:
static public void AddEventsListViewWebPart(PublishingPage page, string webPartZoneId, int zoneIndex, string webPartTitle, PartChromeType webPartChromeType, string listName, string viewname)
{
using (SPLimitedWebPartManager wpManager = page.ListItem.File.GetLimitedWebPartManager(PersonalizationScope.Shared))
{
SPWeb web = page.PublishingWeb.Web;
SPList myList = web.Lists.TryGetList(listName);
using (XsltListViewWebPart lvwp = new XsltListViewWebPart())
{
lvwp.ListName = myList.ID.ToString("B").ToUpperInvariant();
lvwp.Title = webPartTitle;
// Specify the view
SPView view = myList.Views[viewname];
lvwp.ViewGuid = view.ID.ToString("B").ToUpperInvariant();
lvwp.TitleUrl = view.Url;
lvwp.Toolbar = "None";
lvwp.ChromeType = webPartChromeType;
wpManager.AddWebPart(lvwp, webPartZoneId, zoneIndex);
}
}
}
And then call it during feature activation:
AddEventsListViewWebPart(welcomePage, "Right", 1, "Events", PartChromeType.TitleOnly, "Events", "Calendar");

Can I programmatically replace one webpart with another in Sharepoint?

Edit: This is a decade old so very likely not to be relevant to anyone, if google has brought you here I would be sceptical of the content against more modern frameworks!
We have a sharepoint website that has been quite heavily developed with content using the out of the box content editor webpart. This is a bit rubbish when it comes to using any other browser than IE.
We have in mind to update to the free Telerik content editor, however we would like to save ourselves a large amount of copy and pasting, and clicking and selecting to swap the web parts over.
There seems to be no official upgrade path but it seems to me that it must be possible to use the power of code (tm) to grab the content of the original webpart, new up a telerik webopart and put the content into the new webpart... then delete the old original web part.
Has anyone done this sort of thing? How is it best to lay out the code and actually run the code that will do the swap (if it is possible). A fresh webpart with a "Do Swap" button on? or something more sophisticated?
I also would need to walk through every page and subsite (and page in subsite) and look at every web part. Is there a best practice way of doing this?
I would write a console application for this.
Open the root Web and iterate through its sub webs.
Do the work needed for each page, by opening the WebPartManager.
Here are some pseudo code to get you started.
string SourceUrl = "http://ThisWeb";
using (SPSite sourceSite = new SPSite(SourceURL))
{
using (SPWeb sourceWeb = sourceSite.OpenWeb(SourceURL))
{
IterateSubWebsProd(sourceWeb):
}
}
private void IterateSubWebsProd(SPWeb sourceWeb)
{
// This is the migration function
DoThingyWithThisWeb(sourceWeb);
foreach (SPWeb subWeb in sourceWeb.Webs)
{
IterateSubWebsProd(subWeb);
subWeb.Dispose();
}
}
private void DoThingyWithThisWeb(SPWeb sourceWeb)
{
PublishingPage currentPage = null;
string currentPageName = "<something>";
// Find the pages that you want to modify, with a CAML query for example
SPQuery query = new SPQuery();
query.Query = string.Format("" +
"<Where>" +
"<Eq>" +
"<FieldRef Name='FileLeafRef' />" +
"<Value Type='File'>{0}</Value>" +
"</Eq>" +
"</Where>" +
"", currentPageName);
// This codesnippet is from a Publishing web example
PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(sourceWeb);
PublishingPageCollection pageColl = publishingWeb.GetPublishingPages(query);
if (pageColl.Count > 0)
{
currentPage = pageColl[0];
}
using (SPLimitedWebPartManager wpMan = currentPage.ListItem.File.GetLimitedWebPartManager(System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared))
{
foreach (WebPart wp in wpMan.WebParts)
{
if (wp.GetType().Equals(typeof(Microsoft.SharePoint.WebPartPages.ContentEditorWebPart)))
{
Microsoft.SharePoint.WebPartPages.ContentEditorWebPart thisWebPart = wp as Microsoft.SharePoint.WebPartPages.ContentEditorWebPart;
// This is just dummy code, here you will do your content migration
XmlDocument xmlDoc = new XmlDocument();
XmlElement xmlElement = xmlDoc.CreateElement("RootElement");
xmlElement.InnerText = sourceItem[SourceField].ToString();
thisWebPart.Content = xmlElement;
wpMan.SaveChanges(thisWebPart);
}
}
}
}
I'm not 100% certain on this, but if your content is saved into a list as individual fields, could you not point the Telerik controls at where that content is saved? This may cause Telerik controls to freak out a bit on the first edit of that content, but they should be ok to re-format the content and recover.

Resources