CT Survey

======

2. Version

 * XSL-Template vorhanden
 * Ein weiterer Bearbeitungsschritt ist angelegt
 * Es lassen sich FormWidget anlegen und FormSection verwenden
 * Start- und Enddatum ist vorhanden

Ab sofort ist dieser CT abhängig von CT FormSectionItem

git-svn-id: https://svn.libreccm.org/ccm/trunk@355 8810af33-2d31-482b-a856-94f89814c4df
master
quasi 2010-02-19 12:15:58 +00:00
parent 4aae634c33
commit 5d794949de
11 changed files with 280 additions and 102 deletions

View File

@ -8,6 +8,7 @@
<ccm:dependencies>
<ccm:requires name="ccm-core" version="6.6.0" relation="ge"/>
<ccm:requires name="ccm-cms" version="6.6.0" relation="ge"/>
<ccm:requires name="ccm-cms-types-formsectionitem" version="6.6.0" relation="ge"/>
</ccm:dependencies>
<ccm:directories>
<ccm:directory name="pdl"/>

View File

@ -5,39 +5,38 @@ import com.arsdigita.formbuilder.*;
import com.arsdigita.kernel.User;
object type Survey extends ContentPage {
component FormSection[0..1] formSection = join ct_surveys.form_id
to bebop_form_sections.form_section_id;
// Date[0..1] startDate = ct_surveys.start_date DATE;
// Date[0..1] endDate = ct_surveys.end_date DATE;
Boolean[0..1] responsesPublic = ct_surveys.responses_public CHAR(1);
Date[0..1] startDate = ct_surveys.start_date DATE;
Date[0..1] endDate = ct_surveys.end_date DATE;
Boolean[0..1] responsesPublic = ct_surveys.responses_public;
component FormSection[1..1] form = join ct_surveys.form_id
to bebop_form_sections.form_section_id;
reference key ( ct_surveys.survey_id );
}
object type SurveyResponse extends ContentItem {
Survey[1..1] survey = join ct_surveys_responses.survey_id
to ct_surveys.survey_id;
User[1..1] user = join ct_surveys_responses.user_id
to users.user_id;
Date[1..1] entryDate = ct_surveys_responses.entry_date DATE;
Date[1..1] entryDate = ct_surveys_responses.entry_date DATE;
Survey[1..1] survey = join ct_surveys_responses.survey_id
to ct_surveys.survey_id;
User[1..1] user = join ct_surveys_responses.user_id
to users.user_id;
component SurveyAnswer[1..n] answers = join ct_surveys_responses.response_id
to ct_surveys_answers.response_id;
// XXX hack to allow us to filter a data query
BigDecimal[1..1] surveyID = ct_surveys_responses.survey_id INTEGER;
BigDecimal[1..1] userID = ct_surveys_responses.user_id INTEGER;
BigDecimal[1..1] surveyID = ct_surveys_responses.survey_id INTEGER;
BigDecimal[1..1] userID = ct_surveys_responses.user_id INTEGER;
reference key (ct_surveys_responses.response_id);
}
object type SurveyAnswer extends ContentItem{
object type SurveyAnswer extends ContentItem {
Component[1..1] label = join ct_surveys_answers.label_id
to bebop_components.component_id;
Component[1..1] label = join ct_surveys_answers.label_id
to bebop_components.component_id;
Component[1..1] widget = join ct_surveys_answers.widget_id
to bebop_components.component_id;
String[0..1] value = ct_surveys_answers.value VARCHAR(4000);
to bebop_components.component_id;
String[0..1] value = ct_surveys_answers.value VARCHAR(4000);
reference key (ct_surveys_answers.answer_id);
}

View File

@ -21,7 +21,14 @@
component="com.arsdigita.cms.contenttypes.ui.SurveyPropertiesStep"
ordering="1"/>
<ctd:include href="/WEB-INF/content-types/assign-categories-step.xml"/>
<ctd:authoring-step
labelKey="form_item.authoring.controls.title"
labelBundle="com.arsdigita.cms.formbuilder.FormItemResources"
descriptionKey="form_item.authoring.controls.description"
descriptionBundle="com.arsdigita.cms.formbuilder.FormItemResources"
component="com.arsdigita.cms.contenttypes.ui.SurveyControls"/>
<ctd:include href="/WEB-INF/content-types/shared.xml"/>
</ctd:authoring-kit>
</ctd:content-type>

View File

@ -3,14 +3,25 @@
xmlns:xrd="http://xmlns.redhat.com/schemas/waf/xml-renderer-rules"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://rhea.redhat.com/schemas/waf/xml-renderer-rules xml-renderer-rules.xsd">
<!--
Extend adapter for ContentItemPanel to also output the associated objects.
The default properties for BaseContact are left as is and are inherited from ContentPage
-->
<xrd:context name="com.arsdigita.cms.dispatcher.SimpleXMLGenerator">
<xrd:adapter objectType="com.arsdigita.cms.contenttypes.Survey" extends="com.arsdigita.cms.ContentPage">
<xrd:attributes rule="exclude">
<xrd:property name="/object/form/id"/>
<xrd:property name="/object/form/defaultDomainClass"/>
<xrd:property name="/object/form/displayName"/>
</xrd:attributes>
<xrd:associations rule="include">
<xrd:property name="/object/form"/>
<xrd:property name="/object/form/component"/>
<xrd:property name="/object/form/component+"/>
<xrd:property name="/object/form/component/widget"/>
<xrd:property name="/object/form/component/formSectionItem"/>
<xrd:property name="/object/form/component/formSectionItem/formSection"/>
<xrd:property name="/object/form/component/formSectionItem/formSection/component"/>
<xrd:property name="/object/form/component/formSectionItem/formSection/component+"/>
<xrd:property name="/object/form/component/formSectionItem/formSection/component/widget"/>
</xrd:associations>
</xrd:adapter>
</xrd:context>
</xrd:adapters>

View File

@ -4,6 +4,8 @@
<table name="acs_objects"/>
<table name="cms_items"/>
<initializer class="com.arsdigita.cms.Initializer"/>
<table name="cms_form_section_item"/>
<initializer class="com.arsdigita.cms.formbuilder.FormSectionItemInitializer"/>
</requires>
<provides>
<table name="ct_surveys"/>

View File

@ -1,7 +1,6 @@
package com.arsdigita.cms.contenttypes;
import com.arsdigita.cms.ContentPage;
import com.arsdigita.cms.ContentType;
import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.OID;
import com.arsdigita.persistence.SessionManager;
@ -11,7 +10,7 @@ import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.formbuilder.PersistentForm;
import com.arsdigita.util.Assert;
import java.util.Date;
/**
* A survey content type that represents a survey. This is
@ -23,16 +22,28 @@ import com.arsdigita.util.Assert;
public class Survey extends ContentPage {
/** PDL property name for formSection */
public static final String FORM_SECTION = "formSection";
public static final String FORM = "form";
/** PDL property name for startDate */
// public static final String START_DATE = "startDate";
public static final String START_DATE = "startDate";
/** PDL property name for endDate */
// public static final String END_DATE = "endDate";
public static final String END_DATE = "endDate";
/** PDL property name for responsesPublic */
public static final String RESPONSES_PUBLIC = "responsesPublic";
/** Data object type for this domain object */
public static final String BASE_DATA_OBJECT_TYPE = "com.arsdigita.cms.contenttypes.Survey";
/*
private static final SurveyConfig s_config = new SurveyConfig();
static {
s_config.load();
}
public static final SurveyConfig getConfig()
{
return s_config;
}
*/
/**
* Default constructor. This creates a new (empty) Survey.
**/
@ -91,39 +102,62 @@ public class Survey extends ContentPage {
* For new content items, sets the associated content type if it
* has not been already set.
*/
@Override
/* @Override
public void beforeSave() {
super.beforeSave();
super.beforeSave();
Assert.exists(getContentType(), ContentType.class);
Assert.exists(getContentType(), ContentType.class);
}
*/
/**
* This will handle the mandatory FormSection. If there is no
* FormSection set it will create an empty new form and assign it
* to keep the db happy.
*/
@Override
protected void beforeSave() {
if (isNew()) {
if (get(FORM) == null) {
PersistentForm form = new PersistentForm();
form.setHTMLName(getName());
form.setAdminName(getName());
setAssociation(FORM, form);
}
/*
if (getResponsesPublic() == null) {
setResponsesPublic(false);
}
*/
}
super.beforeSave();
}
/* accessors *****************************************************/
public void setForm(PersistentForm persistentForm) {
set(FORM_SECTION, persistentForm);
set(FORM, persistentForm);
}
public PersistentForm getForm() {
return new PersistentForm((DataObject) get(FORM_SECTION));
return new PersistentForm((DataObject) get(FORM));
}
/*
public void setStartDate(Date startDate) {
set(START_DATE, startDate);
set(START_DATE, startDate);
}
public Date getStartDate() {
return (Date)get(START_DATE);
return (Date) get(START_DATE);
}
public void setEndDate(Date endDate) {
set(END_DATE, endDate);
set(END_DATE, endDate);
}
public Date getEndDate() {
return (Date)get(END_DATE);
return (Date) get(END_DATE);
}
*/
public Boolean getResponsesPublic() {
return (Boolean) get(RESPONSES_PUBLIC);
}

View File

@ -0,0 +1,65 @@
package com.arsdigita.cms.contenttypes.ui;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.Container;
import com.arsdigita.bebop.PageState;
import com.arsdigita.cms.ContentItem;
import com.arsdigita.cms.ItemSelectionModel;
import com.arsdigita.cms.SecurityManager;
import com.arsdigita.cms.dispatcher.Utilities;
import com.arsdigita.cms.formbuilder.FormSectionItem;
import com.arsdigita.cms.formbuilder.FormSectionWrapper;
import com.arsdigita.cms.ui.authoring.AuthoringKitWizard;
import com.arsdigita.cms.ui.formbuilder.FormSectionModelBuilder;
import com.arsdigita.cms.ui.workflow.WorkflowLockedContainer;
import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.domain.DomainObjectFactory;
import com.arsdigita.formbuilder.PersistentComponent;
import com.arsdigita.formbuilder.ui.ControlEditor;
import com.arsdigita.persistence.OID;
import com.arsdigita.util.UncheckedWrapperException;
import java.math.BigDecimal;
public class SurveyControls extends ControlEditor {
private ItemSelectionModel m_itemModel;
public SurveyControls(ItemSelectionModel item, AuthoringKitWizard parent) {
super("forms-cms", new SurveySingleSelectionModel(item), true);
m_itemModel = item;
setFormSectionModelBuilder(new FormSectionModelBuilder(item));
}
@Override
protected void addEditableComponent(Container container, Component child) {
WorkflowLockedContainer lock =
new WorkflowLockedContainer(((SurveySingleSelectionModel) getFormModel()).getItemModel());
lock.add(child);
super.addEditableComponent(container, lock);
}
@Override
protected PersistentComponent getFormSection(PageState state, BigDecimal sectionID) {
FormSectionItem section = null;
try {
section = (FormSectionItem) DomainObjectFactory.newInstance(new OID(FormSectionItem.BASE_DATA_OBJECT_TYPE, sectionID));
} catch (DataObjectNotFoundException ex) {
throw new UncheckedWrapperException("cannot load section", ex);
}
FormSectionWrapper wrapper = FormSectionWrapper.create(section, ContentItem.DRAFT);
return wrapper;
}
@Override
protected boolean addItemEditObserver(PageState state) {
return Utilities.getSecurityManager(state).canAccess(
state.getRequest(),
SecurityManager.EDIT_ITEM,
(ContentItem) m_itemModel.getSelectedObject(state));
}
}

View File

@ -28,11 +28,16 @@ import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.FormData;
import com.arsdigita.bebop.event.FormSubmissionListener;
import com.arsdigita.bebop.form.Date;
import com.arsdigita.bebop.form.TextArea;
import com.arsdigita.bebop.form.RadioGroup;
import com.arsdigita.bebop.form.Option;
import com.arsdigita.bebop.parameters.BooleanParameter;
import com.arsdigita.bebop.parameters.DateParameter;
import com.arsdigita.bebop.parameters.DateParameter;
import com.arsdigita.bebop.parameters.NotNullValidationListener;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.bebop.parameters.StringInRangeValidationListener;
import com.arsdigita.bebop.parameters.StringParameter;
@ -45,8 +50,8 @@ public class SurveyPropertiesForm extends BasicPageForm implements FormProcessLi
private SurveyPropertiesStep m_step;
public static final String DESCRIPTION = Survey.DESCRIPTION;
// public static final String START_DATE = Survey.START_DATE;
// public static final String END_DATE = Survey.END_DATE;
public static final String START_DATE = Survey.START_DATE;
public static final String END_DATE = Survey.END_DATE;
public static final String RESPONSES_PUBLIC = Survey.RESPONSES_PUBLIC;
/**
* ID of the form
@ -78,7 +83,7 @@ public class SurveyPropertiesForm extends BasicPageForm implements FormProcessLi
public void addWidgets() {
super.addWidgets();
add(new Label((String) SurveyGlobalizationUtil.globalize("cms.contenttypes.survey.ui.admin.description").localize()));
add(new Label((String) SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.description").localize()));
ParameterModel descriptionParam = new StringParameter(DESCRIPTION);
descriptionParam.addParameterListener(new StringInRangeValidationListener(0, 4000));
TextArea description = new TextArea(descriptionParam);
@ -86,17 +91,20 @@ public class SurveyPropertiesForm extends BasicPageForm implements FormProcessLi
description.setCols(60);
add(description);
// add(new Label(SurveyGlobalizationUtil.globalize("simplesurvey.ui.admin.start_date")));
// add(m_startDate);
//
// add(new Label(SurveyGlobalizationUtil.globalize("simplesurvey.ui.admin.end_date")));
// add(m_endDate);
add(new Label((String) SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.start_date").localize()));
Date startDate = new Date(START_DATE);
add(startDate);
add(new Label((String) SurveyGlobalizationUtil.globalize("cms.contenttypes.survey.ui.admin.should_quiz_responses_be_public").localize()));
add(new Label((String) SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.end_date").localize()));
Date endDate = new Date(END_DATE);
add(endDate);
add(new Label((String) SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.should_quiz_responses_be_public").localize()));
ParameterModel responsesPublicParam = new BooleanParameter(RESPONSES_PUBLIC);
responsesPublicParam.addParameterListener(new NotNullValidationListener());
RadioGroup responsesPublic = new RadioGroup("responsesPublic");
// NotNullValidationListener
Option rp1 = new Option("true", new Label((String) SurveyGlobalizationUtil.globalize("cms.contenttypes.survey.ui.Yes").localize()));
Option rp2 = new Option("false", new Label((String) SurveyGlobalizationUtil.globalize("cms.contenttypes.survey.ui.No").localize()));
Option rp1 = new Option("true", new Label((String) SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.Yes").localize()));
Option rp2 = new Option("false", new Label((String) SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.No").localize()));
responsesPublic.addOption(rp1);
responsesPublic.addOption(rp2);
add(responsesPublic);
@ -109,9 +117,9 @@ public class SurveyPropertiesForm extends BasicPageForm implements FormProcessLi
Survey survey = (Survey) super.initBasicWidgets(e);
data.put(DESCRIPTION, survey.getDescription());
// data.put(START_DATE, survey.getStartDate());
// data.put(END_DATE, survey.getEndDate());
if(survey.getResponsesPublic() != null) {
data.put(START_DATE, survey.getStartDate());
data.put(END_DATE, survey.getEndDate());
if (survey.getResponsesPublic() != null) {
data.put(RESPONSES_PUBLIC, survey.getResponsesPublic().booleanValue());
}
}
@ -124,9 +132,9 @@ public class SurveyPropertiesForm extends BasicPageForm implements FormProcessLi
if ((survey != null) && (getSaveCancelSection().getSaveButton().isSelected(e.getPageState()))) {
survey.setDescription((String) data.get(DESCRIPTION));
// survey.setStartDate((String)data.get(START_DATE));
// survey.setEndDate((String)data.get(END_DATE));
survey.setResponsesPublic(new Boolean((String)data.get(RESPONSES_PUBLIC)));
survey.setStartDate((java.util.Date) data.get(START_DATE));
survey.setEndDate((java.util.Date) data.get(END_DATE));
survey.setResponsesPublic(new Boolean((String) data.get(RESPONSES_PUBLIC)));
survey.save();
}

View File

@ -57,7 +57,7 @@ public class SurveyPropertiesStep extends SimpleEditStep {
basicProperties.add(EDIT_BASIC_SHEET_NAME, (String) SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.edit_basic_properties").localize(), new WorkflowLockedComponentAccess(editBasicSheet, itemModel), editBasicSheet.getSaveCancelSection().getCancelButton());
/* Set the displayComponent for this step */
basicProperties.setDisplayComponent(SurveyPropertiesStep.getSurveyPropertiesSheet(itemModel));
basicProperties.setDisplayComponent(SurveyPropertiesStep.getSurveyPropertiesSheet(itemModel));
/* Add the SimpleEditStep to the segmented panel */
segmentedPanel.addSegment(new Label((String) SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.basic_properties").localize()), basicProperties);
@ -86,21 +86,26 @@ public class SurveyPropertiesStep extends SimpleEditStep {
sheet.add(GlobalizationUtil.globalize("cms.contenttypes.ui.name"), "name");
sheet.add(GlobalizationUtil.globalize("cms.contenttypes.ui.title"), "title");
sheet.add(GlobalizationUtil.globalize("cms.contenttypes.ui.description"), ContentPage.DESCRIPTION);
sheet.add(SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.start_date"), Survey.START_DATE);
sheet.add(SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.end_date"), Survey.END_DATE);
/* Display the Status of ResponsesPublic in localized form */
sheet.add(SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.should_quiz_responses_be_public"), Survey.RESPONSES_PUBLIC, new DomainObjectPropertySheet.AttributeFormatter() {
public String format(DomainObject obj, String attribute, PageState state) {
Survey survey = (Survey) obj;
if (survey.getResponsesPublic() != null) {
if(survey.getResponsesPublic().booleanValue() == true) {
return (String) SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.Yes").localize();
} else{
return (String) SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.No").localize();
}
public String format(DomainObject obj, String attribute, PageState state) {
Survey survey = (Survey) obj;
if (survey.getResponsesPublic() != null) {
if (survey.getResponsesPublic().booleanValue() == true) {
return (String) SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.Yes").localize();
} else {
return (String) GlobalizationUtil.globalize("cms.ui.unknown").localize();
return (String) SurveyGlobalizationUtil.globalize("cms.contenttypes.ui.survey.No").localize();
}
} else {
return (String) GlobalizationUtil.globalize("cms.ui.unknown").localize();
}
});
}
});
if (!ContentSection.getConfig().getHideLaunchDate()) {
sheet.add(GlobalizationUtil.globalize("cms.ui.authoring.page_launch_date"), ContentPage.LAUNCH_DATE, new DomainObjectPropertySheet.AttributeFormatter() {

View File

@ -0,0 +1,55 @@
package com.arsdigita.cms.contenttypes.ui;
import com.arsdigita.bebop.AbstractSingleSelectionModel;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.event.ChangeListener;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.cms.ItemSelectionModel;
import com.arsdigita.cms.contenttypes.Survey;
import com.arsdigita.cms.util.GlobalizationUtil;
public class SurveySingleSelectionModel extends AbstractSingleSelectionModel {
private ItemSelectionModel m_item;
public SurveySingleSelectionModel(ItemSelectionModel item) {
m_item = item;
}
public ItemSelectionModel getItemModel() {
return m_item;
}
@Override
public boolean isSelected(PageState state) {
return m_item.isSelected(state);
}
public Object getSelectedKey(PageState state) {
Survey item = (Survey) m_item.getSelectedObject(state);
return item.getForm().getID();
}
public void setSelectedKey(PageState state, Object key) {
throw new RuntimeException((String) GlobalizationUtil.globalize("cms.ui.formbuilder.oh_no_you_dont").localize());
}
@Override
public void clearSelection(PageState state) {
throw new RuntimeException((String) GlobalizationUtil.globalize("cms.ui.formbuilder.oh_no_you_dont").localize());
}
@Override
public void addChangeListener(ChangeListener l) {
throw new RuntimeException((String) GlobalizationUtil.globalize("cms.ui.formbuilder.oh_no_you_dont").localize());
}
@Override
public void removeChangeListener(ChangeListener l) {
throw new RuntimeException((String) GlobalizationUtil.globalize("cms.ui.formbuilder.oh_no_you_dont").localize());
}
public ParameterModel getStateParameter() {
throw new RuntimeException((String) GlobalizationUtil.globalize("cms.ui.formbuilder.oh_no_you_dont").localize());
}
}

View File

@ -1,41 +1,32 @@
<!DOCTYPE stylesheet [
<!ENTITY nbsp "&#160;" ><!-- no-break space = non-breaking space, U+00A0 ISOnum -->
]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:cms="http://www.arsdigita.com/cms/1.0"
version="1.0">
xmlns:bebop="http://www.arsdigita.com/bebop/1.0"
exclude-result-prefixes="cms bebop">
<xsl:template match="cms:item[objectType='com.arsdigita.cms.contenttypes.BaseContact']" mode="cms:CT_graphics"
name="cms:CT_graphics_com_arsdigita_cms_contenttypes_BaseContact">
<table width="435" border="0" cellspacing="0" cellpadding="0">
<tr>
<td class="contentTitle" align="left" valign="top">
<xsl:value-of select="./title"/>
</td>
</tr>
<tr>
<td>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<xsl:if test="./address">
<tr>
<th>Address:</th>
<td class="contentText" valign="top" align="left"><xsl:value-of select="./address"/></td>
</tr>
</xsl:if>
</table>
</td>
</tr>
</table>
<xsl:import href="../../../../../../packages/formbuilder/xsl/formbuilder.xsl"/>
<xsl:template match="cms:item[objectType='com.arsdigita.cms.contenttypes.Survey']" mode="cms:CT_text"
name="cms:CT_text_com_arsdigita_cms_contenttypes_Survey">
<xsl:apply-templates select="." mode="cms:CT_graphics"/>
<xsl:apply-templates select="form"/>
</xsl:template>
<xsl:template match="cms:item[objectType='com.arsdigita.cms.contenttypes.BaseContact']" mode="cms:CT_text"
name="cms:CT_text_com_arsdigita_cms_contenttypes_BaseContact">
<h1 class="title"><xsl:value-of select="./title"/></h1>
<xsl:if test="./address">
<span class="subtitle">Address</span>
<span class="text"><xsl:value-of select="./address"/></span><br/>
</xsl:if>
<xsl:template match="cms:item[objectType='com.arsdigita.cms.contenttypes.Survey']" mode="cms:CT_graphics"
name="cms:CT_graphics_com_arsdigita_cms_contenttypes_Survey">
<h1><xsl:value-of select="title"/></h1>
<div class="description">
<xsl:value-of select="form/description"/>
</div>
<div>
<xsl:if test="css">
<xsl:attribute name="class">
<xsl:value-of select="css"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="form"/>
</div>
</xsl:template>
</xsl:stylesheet>