Showing posts with label Infopath form. Show all posts
Showing posts with label Infopath form. Show all posts

Tuesday, 23 February 2010

Behind the scene: Property promotion in Infopath

Infopath form has a beautiful feature to promote form fields. When a form is published to a sharepoint document library these promoted fields are available as additional column. This is all good and simple. I'm not going to dig into that in details here.

What I'm trying to focus here is when multiple forms are published to same document library. What happens to these promoted fields. Is the sharepoint list smart enough to figure-out the common columns?

Sharepoint treats all column same and independently. If all attributes are same for a set of promoted filed then they represent same column.

When fields are promoted in Infopath it generates some map behind the scene. This can be viewed in the manifest file using any text of xml editor. For every promoted field it generates a unique id (GUID). And a second map, that maps each promoted to a column. Columns are identified by another GUID.

So every time a new property promotion happens a new set of mapping gets generated. When this happens in two different form naturally all GUID will be different. Therefore even if two form have field with same display name when the are promoted they will generate two different set of mapping guid. And therefore after attaching to a list this fields will be displayed as separate column. Matter of fact it will look like duplicate column. But one of them will display value depending of the content type the current line item is generated from.

The solution is simple. Open the manifest file and make sure common fields have same filed Id and column id. Simply copy one set of mapping from one file and use it for another file. do remember to make sure local form filed reference is correct. I mean it's is referring to the correct local filed in each manifest file.

Republish the form and this time you will see list item generated from both content type are populating same column.

One thing to remember sharepoint will not automatically remove existing set of columns. I mean once you publish one content type and create any list item all columns related to this content type get permanently added to the list. They may not be visible to the current view but they are there. To remove this old column reference you have to recreate the column.
Simply download all item from the list. Recreate the list. republish your content type and upload old item again.

Column and list item realignment will not remove existing column. It will only populate all columns relevant and available with existing items.


Example of column mapping from a manifest file looks like this:


<xsf2:listPropertiesExtension>
<xsf2:fieldsExtension>
<xsf2:fieldExtension columnId="{afd78356-f9c9-4211-8167-7d7d70dc67fd}" readWrite="no" columnName="{E28D210E-FF60-401D-A63A-40AECE533A43}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{26612320-1611-4f71-9197-0382144f7b9a}" readWrite="no" columnName="{32F2028F-BEF8-4B2C-AAE4-9F0753930D7A}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{1DAB9B48-2D1A-47b3-878C-8E84F0D211BA}" readWrite="no" columnName="{5A28EC4B-B173-466F-8814-849B4F932146}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{7cfc7f24-852d-4f78-b1b2-e0e68176d9ba}" readWrite="no" columnName="{D9F232A3-DD04-4B4D-9813-9E15E6549AB7}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{c4e0f350-52cc-4ede-904c-dd71a3d11f7d}" readWrite="no" columnName="{A04C8AD0-074F-4160-8577-E298532A11BA}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{1DAB9B48-2D1A-47b3-878C-8E84F0D211BA}" readWrite="yes" columnName="{0ACC2AC8-0890-496B-B524-D6FA0498C818}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{260962da-788e-458a-82a5-e03bb7f6dc52}" readWrite="yes" columnName="{051DFADD-706C-411B-9A4E-7ABA223CAEA9}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{212ec377-84c6-4c00-ad22-2cab2550fb50}" readWrite="yes" columnName="{00BF28EE-3601-42BA-A1F1-24C74B5A9B35}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{2fdeded3-4b03-47af-8ac6-ca411d5603d4}" readWrite="yes" columnName="{91BB41AA-AD25-4C47-BFE8-E04F175F5AC2}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{bb97a85d-0ee4-46ef-b1f1-0748cfa4c137}" readWrite="yes" columnName="{B463F993-2DAF-47E7-83D0-FD3837044858}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{475a6571-ba0e-4d56-9364-d2ac728a323b}" readWrite="yes" columnName="{8B0055A4-7AE8-4C8F-882C-F0C5E01C90C4}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{fce73a96-7bfa-44e9-8d1b-25d4aaa449ca}" readWrite="yes" columnName="{9535DA33-113B-4091-89AB-4ADC104A0F13}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{2958362e-25af-4d8e-9938-50622a1c0e61}" readWrite="yes" columnName="{C8ECE69F-C5C9-47AF-8E40-17CE03D7F5C4}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{0f26d0d9-9f4f-4de6-829d-a1994b26f7d7}" readWrite="no" columnName="{62A5E596-8726-4BBA-862C-3298BAB6808F}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{19b6647c-8672-46f4-b4da-60c74da4cb04}" readWrite="no" columnName="{F086DE11-7848-40B4-95C4-B1A3CCE1374D}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{9930e1c1-3067-47c1-ab8d-3eeb98679c3f}" readWrite="no" columnName="{B78D2E7D-C8AF-40BB-BAD4-D6D17156A91D}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{b1733cd8-b3ce-42a6-990a-0b9a5955da5c}" readWrite="yes" columnName="{BABE6BC6-F248-4E36-8B86-215345352F89}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{5e295b7a-4849-464e-9d56-92bef86869eb}" readWrite="yes" columnName="{25CF762C-D3BB-4F01-BEA8-7F76C4E09914}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{7f358004-05e4-42ac-9fde-a253039e19ce}" readWrite="yes" columnName="{58E519A7-7FA5-4D37-BF5D-F3057BB2D719}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{33a7da72-2997-4ebf-ad89-9603a478fad2}" readWrite="yes" columnName="{DFB32035-E22F-4EA7-8ED7-D36EFC99586A}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{5571ace5-1274-4388-b2e6-02ea6c3c7c76}" readWrite="yes" columnName="{22D6961D-13BD-465F-8C30-FEF5B0FFC0B0}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{230448c7-3b5b-40e1-8242-dba5c11656ad}" readWrite="yes" columnName="{14CB66B0-EA81-4B26-8ABF-E30C50B61DAB}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{7205c21c-5eae-44b1-9b0e-787bb36de370}" readWrite="no" columnName="{E6B623CF-F7CD-41D5-9059-EC84FD4AD026}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="" readWrite="no" columnName="{C08C7115-ED51-4445-985A-0C747741F8BB}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{eeccc9d8-3a7d-4fb9-9e12-3d72daa3c619}" readWrite="no" columnName="{C1EB52D6-7B01-4A00-BB60-F4279372861A}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{27d7764c-ccfc-433d-828d-56beb602062a}" readWrite="no" columnName="{5FA48CEA-E192-4854-B862-70DBBDAEDBDE}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{40577009-e6a2-44aa-b034-029c61e23f1d}" readWrite="no" columnName="{72522D66-2E9E-4BAA-9C84-8D9BF5F44A37}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{dc455fba-75ab-40e2-8a54-d83ad8d70a6a}" readWrite="no" columnName="{AC0CDC6B-C9B3-4E4A-B341-AC5CC6408CBD}"></xsf2:fieldExtension>
</xsf2:fieldsExtension>
</xsf2:listPropertiesExtension>



And the fields mapping is as follows:

<xsf:listProperties>
<xsf:fields>
<xsf:field name="Reference" columnName="{D9F232A3-DD04-4B4D-9813-9E15E6549AB7}" node="/my:myFields/my:referenceNumber" type="xsd:string"></xsf:field>
<xsf:field name="Job Title" columnName="{A04C8AD0-074F-4160-8577-E298532A11BA}" node="/my:myFields/my:jobTitle" type="xsd:string"></xsf:field>
<xsf:field name="Status" columnName="{0ACC2AC8-0890-496B-B524-D6FA0498C818}" node="/my:myFields/my:status" type="xsd:string"></xsf:field>
<xsf:field name="Business Unit" columnName="{C8ECE69F-C5C9-47AF-8E40-17CE03D7F5C4}" node="/my:myFields/my:businessUnit" type="xsd:string"></xsf:field>
<xsf:field name="Annual Salary" columnName="{62A5E596-8726-4BBA-862C-3298BAB6808F}" node="/my:myFields/my:annualSalary" type="xsd:double"></xsf:field>
<xsf:field name="Country" columnName="{F086DE11-7848-40B4-95C4-B1A3CCE1374D}" node="/my:myFields/my:country" type="xsd:string"></xsf:field>
<xsf:field name="Assigned To" columnName="{BABE6BC6-F248-4E36-8B86-215345352F89}" node="/my:myFields/my:assignedTo" type="xsd:string"></xsf:field>
<xsf:field name="FDGroup Name" columnName="{25CF762C-D3BB-4F01-BEA8-7F76C4E09914}" node="/my:myFields/my:FDGroupName" type="xsd:string"></xsf:field>
<xsf:field name="HRGroup Name" columnName="{58E519A7-7FA5-4D37-BF5D-F3057BB2D719}" node="/my:myFields/my:HRGroupName" type="xsd:string"></xsf:field>
<xsf:field name="MDGroup Name" columnName="{DFB32035-E22F-4EA7-8ED7-D36EFC99586A}" node="/my:myFields/my:MDGroupName" type="xsd:string"></xsf:field>
<xsf:field name="CEOGroup Name" columnName="{22D6961D-13BD-465F-8C30-FEF5B0FFC0B0}" node="/my:myFields/my:CEOGroupName" type="xsd:string"></xsf:field>
<xsf:field name="Submitter Login Name" columnName="{14CB66B0-EA81-4B26-8ABF-E30C50B61DAB}" node="/my:myFields/my:submitterLoginName" type="xsd:string"></xsf:field>
<xsf:field name="Division" columnName="{E6B623CF-F7CD-41D5-9059-EC84FD4AD026}" node="/my:myFields/my:division" type="xsd:string"></xsf:field>
<xsf:field name="Last Modified Login Name" columnName="{C1EB52D6-7B01-4A00-BB60-F4279372861A}" node="/my:myFields/my:LastModifiedLoginName" type="xsd:string"></xsf:field>
<xsf:field name="Current Salary" columnName="{5FA48CEA-E192-4854-B862-70DBBDAEDBDE}" node="/my:myFields/my:currentSalary" type="xsd:double"></xsf:field>
<xsf:field name="Staff Name" columnName="{72522D66-2E9E-4BAA-9C84-8D9BF5F44A37}" node="/my:myFields/my:candidateName" type="xsd:string"></xsf:field>
<xsf:field name="Currency" columnName="{AC0CDC6B-C9B3-4E4A-B341-AC5CC6408CBD}" node="/my:myFields/my:salaryCurrency" type="xsd:string"></xsf:field>
</xsf:fields>
</xsf:listProperties>

There is an unclosed literal string. Line 1, position 411.


I was recently quite scared to see an exception message thrown up from my Infopath form published to a sharepoint list. And most interestingly while I was trying to the same operation from Infopath designer preview, form was working correctly without any exception.
After a bit of search here and there I could not find any solution.
Suddenly I realised that the event causing this exception trying to use a filed which does not exist in the form.

So if you are seeing the same error message most probably your code is trying to access a field that does not exist or you have misspelled the name.

------------ exception message ------------

There is an unclosed literal string. Line 1, position 411.

System.Xml.XmlException: There is an unclosed literal string. Line 1, position 411.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.ParseAttributeValueSlow(Int32 curPos, Char quoteChar, NodeData attr)
at System.Xml.XmlTextReaderImpl.ParseAttributes()
at System.Xml.XmlTextReaderImpl.ParseElement()
at System.Xml.XmlTextReaderImpl.ParseElementContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlLoader.LoadNode(Boolean skipOverWhitespace)
at System.Xml.XmlLoader.LoadDocSequence(XmlDocument parentDoc)
at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
at System.Xml.XmlDocument.Load(XmlReader reader)
at Microsoft.Office.InfoPath.Server.Xml.InfoPathXmlDocument.Load(XmlReader reader)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DataObject.<>c__DisplayClass3.<.ctor>b__0()
at Microsoft.Office.Server.Diagnostics.FirstChanceHandler.ExceptionFilter(Boolean fRethrowException, TryBlock tryBlock, FilterBlock filter, CatchBlock catchBlock, FinallyBlock finallyBlock)
at Microsoft.Office.Server.Diagnostics.ULS.SendWatsonOnExceptionTag(ULSTagID tagID, ULSCat categoryID, String output, Boolean fRethrowException, TryBlock tryBlock, CatchBlock catchBlock, FinallyBlock finallyBlock)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DataObject..ctor(EnhancedBinaryReader reader, Solution solution)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DataObjects.<>c__DisplayClass2.<.ctor>b__0(EnhancedBinaryReader innerReader, DataObject& newObject)
at Microsoft.Office.InfoPath.Server.Serialization.EnhancedBinaryReader.ReadObjectMap[KeyT,ValueT](Dictionary`2 map, ItemReaderDelegate`1 readKey, ItemReaderDelegate`1 readValue)
at Microsoft.Office.InfoPath.Server.Serialization.EnhancedBinaryReader.ReadObjectMap[ValueT](Dictionary`2 map, ItemReaderDelegate`1 readValue)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DataObjects..ctor(EnhancedBinaryReader reader, Solution solution)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DocumentSessionState.DesterilizeVersion1(EnhancedBinaryReader reader, Solution solution)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DocumentSessionState..ctor(EnhancedBinaryReader reader, Solution solution)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DocumentSessionState.CreateFromByteArray(Byte[] serializedSessionState, Byte[] serializedVersionState, Solution solution)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DocumentSessionStateManager.GetSessionState(HttpContext context, String editingSessionID, Solution solution)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.Document.LoadFromSession(HttpContext context, SPSite contextSite, EventLogStart eventLogStart, Solution solution)
at Microsoft.Office.InfoPath.Server.Controls.PostbackPage.<>c__DisplayClass1.b__0()


Tuesday, 29 September 2009

How to keep infopath form in source control

Microsoft infopath form saved with .xsn extension. This is a binary format. If you add a xsn file to source control, you will have record of different version of the form, but you won't be getting the change details.

This can be solved easily by doing it little bit differently. xsn files are basically cab file. And it contains lots of xml, xsd, image and other files. The good thing is Infopath provides a option to save files in its source form, i.e. instead of one big xsn(cab) file, you can save all internal files separately in one location. In that case most of those files are text file. And source control will be able to track all changes in the file.
Save As Source Files option available in the File menu as shown in the image.
And it looks like the image in right.
number of files and types depends on the content of the form. It will always have a manifest file(xsf). Right Click on the manifest file and choose design to open the form in design mode.
There will be xsd files for every data connection/data types. There will be one xsl files for each view, and all images displayed in the form etc.

This makes version controlling worthwhile. Doing this you can merge between branches meaningfully.

One last thing whenever this form is published it will be published as .xsn file in its publish location.

Infopath forn and Branching


Combination of Microsoft Infopath form and source control could turn into a editing hell, specially if that involves branching and merging.
Infopath forms keeps track of where it has been published before and where from it was published. Therefore if the form is moved it gives warning like the one bellow:
This is exactly the same thing happens when source is branched from trunk and is being opened from branch.
Click okay and form is displayed in editable mode. So far it's all right. But when the from is being published again from branch infopath form will ask for saving the file before it can be published even if there has not been any change in the form.
Depending on the user preference, if the always save checkbox is ticked earlier, this dialog box will not appear, instead it will open the file save dialog directly.
That's where the confusion is. In regular publish from does not display the save as box. User can easily confuse about whether that is the publish location it's talking about or the source location.
Infact that's what happened to me. I save the file to it's publish location and then publish it to the same location.
The funniest thing is I've lost all my work. It simply published and stored the original file. All changes are overwritten.

To avoid such loss , I recommend, any time if you move a infopath form do the following thing first:
  • Save the form again to it's new source, make sure path is selected correctly
  • publish to the correct location

I hope this writing will help some one from loosing their days work, just because infopath form doesn't like to move around.