public void startElement(String uri, String localname, String qName, Attributes attributes) throws SAXException { level++; final boolean topLevelElement = level == 1; if (!gotElements) { // Override default as we just go an element assert topLevelElement; delimiterNamespaceURI = uri; delimiterPrefix = XMLUtils.prefixFromQName(qName); delimiterLocalName = XMLUtils.localNameFromQName(qName); gotElements = true; } flushCharacters(false, topLevelElement); generateFirstDelimitersIfNeeded(); // Add or update classes on element if needed super.startElement( uri, localname, qName, topLevelElement ? getAttributesWithClass(attributes) : attributes); }
public class XXFormsIndexChangedEvent extends XFormsUIEvent { private static final String OLD_INDEX_ATTRIBUTE = XMLUtils.buildExplodedQName(XFormsConstants.XXFORMS_NAMESPACE_URI, "old-index"); private static final String NEW_INDEX_ATTRIBUTE = XMLUtils.buildExplodedQName(XFormsConstants.XXFORMS_NAMESPACE_URI, "new-index"); private int oldIndex; private int newIndex; public XXFormsIndexChangedEvent( XFormsContainingDocument containingDocument, XFormsControl targetObject, int oldIndex, int newIndex) { super(containingDocument, XFormsEvents.XXFORMS_INDEX_CHANGED, targetObject); this.oldIndex = oldIndex; this.newIndex = newIndex; } @Override public SequenceIterator getAttribute(String name) { if (OLD_INDEX_ATTRIBUTE.equals(name)) { return SingletonIterator.makeIterator(new Int64Value(oldIndex)); } else if (NEW_INDEX_ATTRIBUTE.equals(name)) { return SingletonIterator.makeIterator(new Int64Value(newIndex)); } else { return super.getAttribute(name); } } }
@Override public void handleControlStart( String uri, String localname, String qName, Attributes attributes, String staticId, final String effectiveId, XFormsSingleNodeControl xformsControl) throws SAXException { final String groupElementName = getContainingElementName(); final String xhtmlPrefix = handlerContext.findXHTMLPrefix(); final String groupElementQName = XMLUtils.buildQName(xhtmlPrefix, groupElementName); final ElementHandlerController controller = handlerContext.getController(); // Get classes // TODO: should use getContainerAttributes() instead? final StringBuilder classes = getInitialClasses(uri, localname, attributes, null); handleMIPClasses(classes, getPrefixedId(), xformsControl); final ContentHandler contentHandler = controller.getOutput(); // Start xhtml:fieldset element if needed if (!handlerContext.isNewXHTMLLayout()) contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, groupElementName, groupElementQName, getAttributes(attributes, classes.toString(), effectiveId)); // Output an xhtml:legend element if and only if there is an xforms:label element. This help // with // styling in particular. final boolean hasLabel = XFormsControl.hasLabel(containingDocument, getPrefixedId()); if (hasLabel) { // Handle label classes reusableAttributes.clear(); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, getLabelClasses(xformsControl)); // The id should never be need on <legend> // reusableAttributes.addAttribute("", "id", "id", ContentHandlerHelper.CDATA, // getLHHACId(effectiveId, LHHAC_CODES.get(LHHAC.LABEL))); // Output xhtml:legend with label content final String legendQName = XMLUtils.buildQName(xhtmlPrefix, "legend"); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "legend", legendQName, reusableAttributes); { final String labelValue = getLabelValue(xformsControl); if (StringUtils.isNotEmpty(labelValue)) contentHandler.characters(labelValue.toCharArray(), 0, labelValue.length()); } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "legend", legendQName); } }
private void checkDelimiters(String uri, String qName, boolean topLevel) throws SAXException { if (topLevel && delimiterNamespaceURI == null) { delimiterNamespaceURI = uri; delimiterPrefix = XMLUtils.prefixFromQName(qName); delimiterLocalName = XMLUtils.localNameFromQName(qName); } if (mustGenerateFirstDelimiters) { // Generate first delimiter beginDelimiterListener.generateFirstDelimiter(this); mustGenerateFirstDelimiters = false; } }
public OutputInterceptor( XMLReceiver output, String spanQName, Listener beginDelimiterListener, boolean isAroundTableOrListElement) { super(output); this.spanQName = spanQName; this.beginDelimiterListener = beginDelimiterListener; this.isAroundTableOrListElement = isAroundTableOrListElement; // Default to <xhtml:span> delimiterNamespaceURI = XMLConstants.XHTML_NAMESPACE_URI; delimiterPrefix = XMLUtils.prefixFromQName(spanQName); delimiterLocalName = XMLUtils.localNameFromQName(spanQName); }
protected void handleControlStart( String uri, String localname, String qName, Attributes attributes, String effectiveId, XFormsControl control) throws SAXException { final XFormsTriggerControl triggerControl = (XFormsTriggerControl) control; final XMLReceiver xmlReceiver = handlerContext.getController().getOutput(); final AttributesImpl containerAttributes = getEmptyNestedControlAttributesMaybeWithId( uri, localname, attributes, effectiveId, triggerControl, true); // TODO: needs f:url-norewrite="true"? containerAttributes.addAttribute("", "href", "href", XMLReceiverHelper.CDATA, "#"); // xhtml:a final String xhtmlPrefix = handlerContext.findXHTMLPrefix(); final String aQName = XMLUtils.buildQName(xhtmlPrefix, ENCLOSING_ELEMENT_NAME); xmlReceiver.startElement( XMLConstants.XHTML_NAMESPACE_URI, ENCLOSING_ELEMENT_NAME, aQName, containerAttributes); { final String labelValue = getTriggerLabel(triggerControl); final boolean mustOutputHTMLFragment = triggerControl != null && triggerControl.isHTMLLabel(); outputLabelText(xmlReceiver, triggerControl, labelValue, xhtmlPrefix, mustOutputHTMLFragment); } xmlReceiver.endElement(XMLConstants.XHTML_NAMESPACE_URI, ENCLOSING_ELEMENT_NAME, aQName); }
/** * Convert a String in xs:anyURI to an xs:base64Binary. * * <p>The URI has to be a URL. It is read entirely */ public static String anyURIToBase64Binary(String value) { InputStream is = null; try { // Read from URL and convert to Base64 is = URLFactory.createURL(value).openStream(); final StringBuffer sb = new StringBuffer(); XMLUtils.inputStreamToBase64Characters( is, new ContentHandlerAdapter() { public void characters(char ch[], int start, int length) { sb.append(ch, start, length); } }); // Return Base64 String return sb.toString(); } catch (IOException e) { throw new OXFException(e); } finally { if (is != null) { try { is.close(); } catch (IOException e) { throw new OXFException(e); } } } }
@Test public void formNamespaceElements() { final Metadata metadata = new Metadata(); final XFormsAnnotatorContentHandler ch = new XFormsAnnotatorContentHandler(metadata); XMLUtils.urlToSAX( "oxf:/org/orbeon/oxf/xforms/processor/test-form.xml", ch, XMLUtils.ParserConfiguration.PLAIN, false); // Test that ns information is provided for those elements assertNotNull(metadata.getNamespaceMapping("output-in-title").mapping); assertNotNull(metadata.getNamespaceMapping("html").mapping); assertNotNull(metadata.getNamespaceMapping("main-instance").mapping); assertNotNull(metadata.getNamespaceMapping("dateTime-component").mapping); assertNotNull(metadata.getNamespaceMapping("dateTime1-control").mapping); assertNotNull(metadata.getNamespaceMapping("value1-control").mapping); assertNotNull(metadata.getNamespaceMapping("output-in-label").mapping); assertNotNull(metadata.getNamespaceMapping("img-in-label").mapping); assertNotNull(metadata.getNamespaceMapping("span").mapping); // Test that ns information is NOT provided for those elements (because processed as part of // shadow tree processing) assertNull(metadata.getNamespaceMapping("instance-in-xbl")); assertNull(metadata.getNamespaceMapping("div-in-xbl")); // Test that ns information is NOT provided for those elements (because in instances or schemas) assertNull(metadata.getNamespaceMapping("instance-root")); assertNull(metadata.getNamespaceMapping("instance-value")); assertNull(metadata.getNamespaceMapping("xbl-instance-root")); assertNull(metadata.getNamespaceMapping("xbl-instance-value")); assertNull(metadata.getNamespaceMapping("schema-element")); }
/** Transform an InputStream to a TinyTree. */ public static DocumentInfo readTinyTree( Configuration configuration, InputStream inputStream, String systemId, boolean handleXInclude, boolean handleLexical) { final TinyBuilder treeBuilder = new TinyBuilder(); { final TransformerXMLReceiver identityHandler = getIdentityTransformerHandler(configuration); identityHandler.setResult(treeBuilder); final XMLReceiver xmlReceiver; if (handleXInclude) { // Insert XIncludeContentHandler xmlReceiver = new XIncludeProcessor.XIncludeXMLReceiver( null, identityHandler, null, new TransformerURIResolver(XMLUtils.ParserConfiguration.PLAIN)); } else { xmlReceiver = identityHandler; } XMLUtils.inputStreamToSAX( inputStream, systemId, xmlReceiver, XMLUtils.ParserConfiguration.PLAIN, handleLexical); } return (DocumentInfo) treeBuilder.getCurrentRoot(); }
public void deserialize( PropertyContext propertyContext, ConnectionResult connectionResult, XFormsModelSubmission.SubmissionParameters p, XFormsModelSubmission.SecondPassParameters p2) throws Exception { // Deserialize here so it can run in parallel if (XMLUtils.isXMLMediatype(connectionResult.getResponseMediaType())) { // XML media type final IndentedLogger detailsLogger = getDetailsLogger(p, p2); resultingDocument = deserializeInstance( propertyContext, detailsLogger, p2.isReadonly, p2.isHandleXInclude, connectionResult); } else { // Other media type is not allowed throw new XFormsSubmissionException( submission, "Body received with non-XML media type for replace=\"instance\": " + connectionResult.getResponseMediaType(), "processing instance replacement", new XFormsSubmitErrorEvent( containingDocument, propertyContext, submission, XFormsSubmitErrorEvent.ErrorType.RESOURCE_ERROR, connectionResult)); } }
public static XMLReader newXMLReader(XMLUtils.ParserConfiguration parserConfiguration) { final SAXParser saxParser = XMLUtils.newSAXParser(parserConfiguration); try { final XMLReader xmlReader = saxParser.getXMLReader(); xmlReader.setEntityResolver(XMLUtils.ENTITY_RESOLVER); xmlReader.setErrorHandler(XMLUtils.ERROR_HANDLER); return xmlReader; } catch (Exception e) { throw new OXFException(e); } }
private static void mapPrefixIfNeeded( Set<String> declaredPrefixes, String uri, String qName, StringBuilder sb) { final String prefix = XMLUtils.prefixFromQName(qName); if (prefix.length() > 0 && !declaredPrefixes.contains(prefix)) { sb.append(" xmlns:"); sb.append(prefix); sb.append("=\""); sb.append(uri); sb.append("\""); declaredPrefixes.add(prefix); } }
public void outputDelimiter(ContentHandler contentHandler, String classes, String id) throws SAXException { reusableAttributes.clear(); if (id != null) reusableAttributes.addAttribute("", "id", "id", ContentHandlerHelper.CDATA, id); if (classes != null) reusableAttributes.addAttribute("", "class", "class", ContentHandlerHelper.CDATA, classes); final String delimiterQName = XMLUtils.buildQName(delimiterPrefix, delimiterLocalName); contentHandler.startElement( delimiterNamespaceURI, delimiterLocalName, delimiterQName, reusableAttributes); contentHandler.endElement(delimiterNamespaceURI, delimiterLocalName, delimiterQName); }
public static AttributesImpl addOrReplaceAttribute( Attributes attributes, String uri, String prefix, String localname, String value) { final AttributesImpl newAttributes = new AttributesImpl(); boolean replaced = false; for (int i = 0; i < attributes.getLength(); i++) { final String attributeURI = attributes.getURI(i); final String attributeValue = attributes.getValue(i); final String attributeType = attributes.getType(i); final String attributeQName = attributes.getQName(i); final String attributeLocalname = attributes.getLocalName(i); if (uri.equals(attributeURI) && localname.equals(attributeLocalname)) { // Found existing attribute replaced = true; newAttributes.addAttribute( uri, localname, XMLUtils.buildQName(prefix, localname), ContentHandlerHelper.CDATA, value); } else { // Not a matched attribute newAttributes.addAttribute( attributeURI, attributeLocalname, attributeQName, attributeType, attributeValue); } } if (!replaced) { // Attribute did not exist already so add it newAttributes.addAttribute( uri, localname, XMLUtils.buildQName(prefix, localname), ContentHandlerHelper.CDATA, value); } return newAttributes; }
private Attributes getAttributesWithClass(Attributes originalAttributes) { String newClassAttribute = originalAttributes.getValue("class"); if (addedClasses != null && addedClasses.length() > 0) { if (newClassAttribute == null || newClassAttribute.length() == 0) { newClassAttribute = addedClasses; } else { newClassAttribute += " " + addedClasses; } } if (newClassAttribute != null) return XMLUtils.addOrReplaceAttribute(originalAttributes, "", "", "class", newClassAttribute); else return originalAttributes; }
/** Transform an InputStream to a dom4j Document. */ public static Document readDom4j( InputStream inputStream, String systemId, boolean handleXInclude, boolean handleLexical) { final LocationSAXContentHandler dom4jResult = new LocationSAXContentHandler(); { final XMLReceiver xmlReceiver; if (handleXInclude) { // Insert XIncludeContentHandler xmlReceiver = new XIncludeProcessor.XIncludeXMLReceiver( null, dom4jResult, null, new TransformerURIResolver(XMLUtils.ParserConfiguration.PLAIN)); } else { xmlReceiver = dom4jResult; } XMLUtils.inputStreamToSAX( inputStream, systemId, xmlReceiver, XMLUtils.ParserConfiguration.PLAIN, handleLexical); } return dom4jResult.getDocument(); }
@Override public void handleControlEnd( String uri, String localname, String qName, Attributes attributes, String staticId, String effectiveId, XFormsSingleNodeControl xformsControl) throws SAXException { final ElementHandlerController controller = handlerContext.getController(); // Close xhtml:span final String xhtmlPrefix = handlerContext.findXHTMLPrefix(); final String groupElementName = getContainingElementName(); final String groupElementQName = XMLUtils.buildQName(xhtmlPrefix, groupElementName); if (!handlerContext.isNewXHTMLLayout()) controller .getOutput() .endElement(XMLConstants.XHTML_NAMESPACE_URI, groupElementName, groupElementQName); }
/** * Return the charset associated with a text/* Content-Type header. If a charset is present, * return it. Otherwise, guess depending on whether the mediatype is text/xml or not. * * @param contentType Content-Type header value * @return charset */ public static String getTextCharsetFromContentType(String contentType) { final String charset; final String connectionCharset = getContentTypeCharset(contentType); if (connectionCharset != null) { charset = connectionCharset; } else { // RFC 3023: "Conformant with [RFC2046], if a text/xml entity is // received with the charset parameter omitted, MIME processors and // XML processors MUST use the default charset value of // "us-ascii"[ASCII]. In cases where the XML MIME entity is // transmitted via HTTP, the default charset value is still // "us-ascii". (Note: There is an inconsistency between this // specification and HTTP/1.1, which uses ISO-8859-1[ISO8859] as the // default for a historical reason. Since XML is a new format, a new // default should be chosen for better I18N. US-ASCII was chosen, // since it is the intersection of UTF-8 and ISO-8859-1 and since it // is already used by MIME.)" if (XMLUtils.isXMLMediatype(contentType)) charset = DEFAULT_TEXT_XML_READING_ENCODING; else charset = DEFAULT_HTTP_TEXT_READING_ENCODING; } return charset; }
public void startElement(String uri, String localname, String qName, Attributes attributes) throws SAXException { namespaceSupport.startElement(); // Handle location data if (locationData == null && locator != null && mustOutputFirstElement) { final String systemId = locator.getSystemId(); if (systemId != null) { locationData = new LocationData(systemId, locator.getLineNumber(), locator.getColumnNumber()); } } // Check for XForms or extension namespaces final boolean isXForms = XFormsConstants.XFORMS_NAMESPACE_URI.equals(uri); final boolean isXXForms = XFormsConstants.XXFORMS_NAMESPACE_URI.equals(uri); final boolean isEXForms = XFormsConstants.EXFORMS_NAMESPACE_URI.equals(uri); final boolean isXBL = XFormsConstants.XBL_NAMESPACE_URI.equals(uri); final boolean isXHTML = XMLConstants.XHTML_NAMESPACE_URI.equals(uri); // TODO: how else can we handle components? // NOTE: Here we have an issue identifying which elements must have content preserved. For // example, an element // to which an XBL binding is applied should be preserved, because XBL template processing take // place during // static state analysis. In XFormsDocumentAnnotatorContentHandler, we detect XBL bindings. // Should we do the // same here again? It is wasteful to do it twice. Possibly, XFDACH could pass this information // here since // it already does all the work to detect content preservation. E.g. custom attribute. // final boolean isXFormsOrExtension = isXForms || isXXForms || isEXForms || isXBL; final boolean isXFormsOrExtension = !isXHTML && !"".equals(uri); // see NOTE above final boolean isExtension = isXFormsOrExtension && !isXForms && !isXXForms && !isEXForms && !isXBL; // see NOTE above // Handle xml:base if (!inXFormsOrExtension) { final String xmlBaseAttribute = attributes.getValue(XMLConstants.XML_URI, "base"); if (xmlBaseAttribute == null) { xmlBaseStack.push(xmlBaseStack.peek()); } else { try { final URI currentXMLBaseURI = xmlBaseStack.peek(); xmlBaseStack.push( currentXMLBaseURI .resolve(new URI(xmlBaseAttribute)) .normalize()); // normalize to remove "..", etc. } catch (URISyntaxException e) { throw new ValidationException( "Error creating URI from: '" + xmlBaseStack.peek() + "' and '" + xmlBaseAttribute + "'.", e, new LocationData(locator)); } } } // Handle properties of the form @xxforms:* when outside of models or controls if (!inXFormsOrExtension && !isXFormsOrExtension) { final int attributesCount = attributes.getLength(); for (int i = 0; i < attributesCount; i++) { final String attributeURI = attributes.getURI(i); if (XFormsConstants.XXFORMS_NAMESPACE_URI.equals(attributeURI)) { // Found xxforms:* attribute final String attributeLocalName = attributes.getLocalName(i); // Only take the first occurrence into account, and make sure the property is supported if (properties.get(attributeLocalName) == null && XFormsProperties.getPropertyDefinition(attributeLocalName) != null) { properties.put(attributeLocalName, attributes.getValue(i)); } } } } if (level > 0 || !ignoreRootElement) { // Start extracting model or controls if (!inXFormsOrExtension && isXFormsOrExtension) { inXFormsOrExtension = true; xformsLevel = level; outputFirstElementIfNeeded(); // Add xml:base on element attributes = XMLUtils.addOrReplaceAttribute( attributes, XMLConstants.XML_URI, "xml", "base", getCurrentBaseURI()); sendStartPrefixMappings(); } // Check for preserved content if (inXFormsOrExtension && !inPreserve) { // TODO: Just warn? if (isXXForms) { // Check that we are getting a valid xxforms:* element if (XFormsConstants.ALLOWED_XXFORMS_ELEMENTS.get(localname) == null && !XFormsActions.isActionName(XFormsConstants.XXFORMS_NAMESPACE_URI, localname)) throw new ValidationException( "Invalid extension element in XForms document: " + qName, new LocationData(locator)); } else if (isEXForms) { // Check that we are getting a valid exforms:* element if (XFormsConstants.ALLOWED_EXFORMS_ELEMENTS.get(localname) == null) throw new ValidationException( "Invalid eXForms element in XForms document: " + qName, new LocationData(locator)); } else if (isXBL) { // Check that we are getting a valid xbl:* element if (XFormsConstants.ALLOWED_XBL_ELEMENTS.get(localname) == null) throw new ValidationException( "Invalid XBL element in XForms document: " + qName, new LocationData(locator)); } // Preserve as is the content of labels, etc., instances, and schemas if ((XFormsConstants.LABEL_HINT_HELP_ALERT_ELEMENT.get(localname) != null // labels, etc. may contain XHTML || "instance".equals(localname)) && isXForms // XForms instances || "schema".equals(localname) && XMLConstants.XSD_URI.equals(uri) // XML schemas || "xbl".equals(localname) && isXBL // preserve everything under xbl:xbl so that templates may be processed by // static state || isExtension) { inPreserve = true; preserveLevel = level; } } // We are within preserved content or we output regular XForms content if (inXFormsOrExtension && (inPreserve || isXFormsOrExtension)) { super.startElement(uri, localname, qName, attributes); } } else { // Just open the root element outputFirstElementIfNeeded(); sendStartPrefixMappings(); super.startElement(uri, localname, qName, attributes); } level++; }
public void handleControlStart( String uri, String localname, String qName, Attributes attributes, final String effectiveId, XFormsControl control) throws SAXException { final String groupElementName = getContainingElementName(); final String xhtmlPrefix = handlerContext.findXHTMLPrefix(); final String groupElementQName = XMLUtils.buildQName(xhtmlPrefix, groupElementName); final ElementHandlerController controller = handlerContext.getController(); // Place interceptor on output // NOTE: Strictly, we should be able to do without the interceptor. We use it here because it // automatically handles ids and element names currentSavedOutput = controller.getOutput(); if (!handlerContext.isNoScript()) { final boolean isMustGenerateBeginEndDelimiters = !handlerContext.isFullUpdateTopLevelControl(effectiveId); // Classes on top-level elements and characters and on the first delimiter final String elementClasses; { final StringBuilder classes = new StringBuilder(); appendControlUserClasses(attributes, control, classes); // NOTE: Could also use getInitialClasses(uri, localname, attributes, control), but then we // get the // xforms-group-appearance-xxforms-separator class. Is that desirable? handleMIPClasses( classes, getPrefixedId(), control); // as of August 2009, actually only need the marker class as well as // xforms-disabled if the group is non-relevant elementClasses = classes.toString(); } outputInterceptor = new OutputInterceptor( currentSavedOutput, groupElementQName, new OutputInterceptor.Listener() { // Classes on first delimiter private final String firstDelimiterClasses; { final StringBuilder classes = new StringBuilder("xforms-group-begin-end"); if (elementClasses.length() > 0) { classes.append(' '); classes.append(elementClasses); } firstDelimiterClasses = classes.toString(); } public void generateFirstDelimiter(OutputInterceptor outputInterceptor) throws SAXException { // Delimiter: begin group if (isMustGenerateBeginEndDelimiters) { outputInterceptor.outputDelimiter( currentSavedOutput, outputInterceptor.getDelimiterNamespaceURI(), outputInterceptor.getDelimiterPrefix(), outputInterceptor.getDelimiterLocalName(), firstDelimiterClasses, "group-begin-" + XFormsUtils.namespaceId(containingDocument, effectiveId)); } } }); controller.setOutput(new DeferredXMLReceiverImpl(outputInterceptor)); // Set control classes outputInterceptor.setAddedClasses(elementClasses); } else if (isNonRelevant(control)) { // In noscript, if the group not visible, set output to a black hole controller.setOutput(new DeferredXMLReceiverAdapter()); } // Don't support label, help, alert, or hint and other appearances, only the content! }
@Override protected void handleControlStart( String uri, String localname, String qName, Attributes attributes, String staticId, final String effectiveId, XFormsControl control) throws SAXException { final String xhtmlPrefix = handlerContext.findXHTMLPrefix(); final String spanQName = XMLUtils.buildQName(xhtmlPrefix, "span"); // Determine whether this case is visible final XFormsCaseControl caseControl = (XFormsCaseControl) containingDocument.getControls().getObjectByEffectiveId(effectiveId); if (!handlerContext.isTemplate() && caseControl != null) { // This case is visible if it is selected or if the switch is read-only and we display // read-only as static isVisible = caseControl.isVisible(); } else { isVisible = false; } final ElementHandlerController controller = handlerContext.getController(); currentSavedOutput = controller.getOutput(); // Place interceptor if needed if (!handlerContext.isNoScript()) { final boolean isMustGenerateBeginEndDelimiters = !handlerContext.isFullUpdateTopLevelControl(effectiveId); // Classes on top-level elements and characters and on the first delimiter final String elementClasses; { final StringBuilder classes = new StringBuilder(); appendControlUserClasses(attributes, control, classes); // Don't add MIP classes as they can conflict with classes of nested content if used outside // <tr>, etc. elementClasses = classes.toString(); } currentOutputInterceptor = new OutputInterceptor( currentSavedOutput, spanQName, new OutputInterceptor.Listener() { // Classes on first delimiter private final String firstDelimiterClasses; { final StringBuilder classes = new StringBuilder("xforms-case-begin-end"); if (elementClasses.length() > 0) { classes.append(' '); classes.append(elementClasses); } firstDelimiterClasses = classes.toString(); } public void generateFirstDelimiter(OutputInterceptor outputInterceptor) throws SAXException { if (isMustGenerateBeginEndDelimiters) { // Delimiter: begin case outputInterceptor.outputDelimiter( currentSavedOutput, outputInterceptor.getDelimiterNamespaceURI(), outputInterceptor.getDelimiterPrefix(), outputInterceptor.getDelimiterLocalName(), firstDelimiterClasses, "xforms-case-begin-" + XFormsUtils.namespaceId(containingDocument, effectiveId)); } } }); final String controlClasses; { final StringBuilder classes = new StringBuilder(isVisible ? "xforms-case-selected" : "xforms-case-deselected"); if (elementClasses.length() > 0) { classes.append(' '); classes.append(elementClasses); } controlClasses = classes.toString(); } currentOutputInterceptor.setAddedClasses(controlClasses); controller.setOutput(new DeferredXMLReceiverImpl(currentOutputInterceptor)); } else if (!isVisible) { // Case not visible, set output to a black hole controller.setOutput(new DeferredXMLReceiverAdapter()); } handlerContext.pushCaseContext(isVisible); }
public void outputContent( String uri, String localname, Attributes attributes, String effectiveId, final XFormsValueControl xformsSelect1Control, Itemset itemset, final boolean isMultiple, final boolean isFull, boolean isBooleanInput) throws SAXException { final ContentHandler contentHandler = handlerContext.getController().getOutput(); final AttributesImpl containerAttributes = getContainerAttributes( uri, localname, attributes, effectiveId, xformsSelect1Control, !isFull); final String xhtmlPrefix = handlerContext.findXHTMLPrefix(); if (!isStaticReadonly(xformsSelect1Control)) { if (isFull) { // Full appearance outputFull( uri, localname, attributes, effectiveId, xformsSelect1Control, itemset, isMultiple, isBooleanInput); } else { if (isOpenSelection) { if (isAutocomplete) { // Create xhtml:span final String spanQName = XMLUtils.buildQName(xhtmlPrefix, "span"); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "span", spanQName, containerAttributes); { { // Create xhtml:input final String inputQName = XMLUtils.buildQName(xhtmlPrefix, "input"); reusableAttributes.clear(); reusableAttributes.addAttribute( "", "type", "type", ContentHandlerHelper.CDATA, "text"); reusableAttributes.addAttribute( "", "name", "name", ContentHandlerHelper.CDATA, "xforms-select1-open-input-" + effectiveId); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, "xforms-select1-open-input"); reusableAttributes.addAttribute( "", "autocomplete", "autocomplete", ContentHandlerHelper.CDATA, "off"); final String value = (xformsSelect1Control == null) ? null : xformsSelect1Control.getValue(pipelineContext); // NOTE: With open selection, we send all values to the client but not encrypt them // because the client matches on values reusableAttributes.addAttribute( "", "value", "value", ContentHandlerHelper.CDATA, (value == null) ? "" : value); handleDisabledAttribute( reusableAttributes, containingDocument, xformsSelect1Control); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "input", inputQName, reusableAttributes); contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "input", inputQName); } { // Create xhtml:select final String selectQName = XMLUtils.buildQName(xhtmlPrefix, "select"); reusableAttributes.clear(); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, "xforms-select1-open-select"); if (isCompact) reusableAttributes.addAttribute( "", "multiple", "multiple", ContentHandlerHelper.CDATA, "multiple"); // Handle accessibility attributes handleAccessibilityAttributes(attributes, reusableAttributes); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "select", selectQName, reusableAttributes); final String optionQName = XMLUtils.buildQName(xhtmlPrefix, "option"); handleItemCompact( contentHandler, optionQName, xformsSelect1Control, isMultiple, EMPTY_TOP_LEVEL_ITEM); if (itemset != null) { for (final Item item : itemset.toList()) { if (item.getValue() != null) handleItemCompact( contentHandler, optionQName, xformsSelect1Control, isMultiple, item); } } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "select", selectQName); } } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "span", spanQName); } else { // We do not support other appearances or regular open selection for now throw new ValidationException( "Open selection currently only supports the xxforms:autocomplete appearance.", new ExtendedLocationData( handlerContext.getLocationData(), "producing markup for xforms:" + localname + " control", (xformsSelect1Control != null) ? xformsSelect1Control.getControlElement() : null)); } } else if (isTree) { // xxforms:tree appearance // Create xhtml:div with tree info final String divQName = XMLUtils.buildQName(xhtmlPrefix, "div"); handleDisabledAttribute(containerAttributes, containingDocument, xformsSelect1Control); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "div", divQName, containerAttributes); if (itemset != null) { // can be null if the control is non-relevant outputJSONTreeInfo(xformsSelect1Control, itemset, isMultiple, contentHandler); } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "div", divQName); } else if (isMenu) { // xxforms:menu appearance // Create enclosing xhtml:div final String divQName = XMLUtils.buildQName(xhtmlPrefix, "div"); final String ulQName = XMLUtils.buildQName(xhtmlPrefix, "ul"); final String liQName = XMLUtils.buildQName(xhtmlPrefix, "li"); final String aQName = XMLUtils.buildQName(xhtmlPrefix, "a"); handleDisabledAttribute(containerAttributes, containingDocument, xformsSelect1Control); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "div", divQName, containerAttributes); if (itemset != null) { // can be null if the control is non-relevant // Create xhtml:div with initial menu entries { itemset.visit( contentHandler, new ItemsetListener() { private boolean groupJustStarted = false; public void startLevel(ContentHandler contentHandler, Item item) throws SAXException { final boolean isTopLevel = item == null; reusableAttributes.clear(); final String divClasses = isTopLevel ? "yuimenubar" : "yuimenu"; reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, divClasses); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "div", divQName, reusableAttributes); reusableAttributes.clear(); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, "bd"); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "div", divQName, reusableAttributes); reusableAttributes.clear(); // NOTE: We just decide to put item classes on <ul> final String classes = isTopLevel ? "first-of-type" : getItemClasses(item, "first-of-type"); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, classes); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "ul", ulQName, reusableAttributes); groupJustStarted = true; } public void endLevel(ContentHandler contentHandler) throws SAXException { contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "ul", ulQName); contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "div", divQName); contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "div", divQName); groupJustStarted = false; } public void startItem(ContentHandler contentHandler, Item item, boolean first) throws SAXException { final String liClasses; { final StringBuilder sb = new StringBuilder(item.isTopLevel() ? "yuimenubaritem" : "yuimenuitem"); if (groupJustStarted) sb.append(" first-of-type"); liClasses = getItemClasses(item, sb.toString()); } reusableAttributes.clear(); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, liClasses); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "li", liQName, reusableAttributes); reusableAttributes.clear(); reusableAttributes.addAttribute( "", "href", "href", ContentHandlerHelper.CDATA, "#"); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "a", aQName, reusableAttributes); final String text = item.getLabel(); contentHandler.characters(text.toCharArray(), 0, text.length()); contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "a", aQName); groupJustStarted = false; } public void endItem(ContentHandler contentHandler) throws SAXException { contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "li", liQName); groupJustStarted = false; } }); } // Create xhtml:div with tree info reusableAttributes.clear(); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, "xforms-initially-hidden"); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "div", divQName, reusableAttributes); if (itemset != null) { // can be null if the control is non-relevant outputJSONTreeInfo(xformsSelect1Control, itemset, isMultiple, contentHandler); } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "div", divQName); } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "div", divQName); } else { // Create xhtml:select final String selectQName = XMLUtils.buildQName(xhtmlPrefix, "select"); containerAttributes.addAttribute( "", "name", "name", ContentHandlerHelper.CDATA, effectiveId); // necessary for noscript mode if (isCompact) containerAttributes.addAttribute( "", "multiple", "multiple", ContentHandlerHelper.CDATA, "multiple"); // Handle accessibility attributes handleAccessibilityAttributes(attributes, containerAttributes); handleDisabledAttribute(containerAttributes, containingDocument, xformsSelect1Control); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "select", selectQName, containerAttributes); { final String optionQName = XMLUtils.buildQName(xhtmlPrefix, "option"); final String optGroupQName = XMLUtils.buildQName(xhtmlPrefix, "optgroup"); if (itemset != null) { // Work in progress for in-bounds/out-of-bounds // if (!((XFormsSelect1Control) // xformsControl).isInBounds(items)) { // // Control is out of bounds so add first item with out // of bound value to handle this // handleItemCompact(contentHandler, optionQName, // xformsControl, isMultiple, // new // XFormsItemUtils.Item(XFormsProperties.isEncryptItemValues(containingDocument), // Collections.EMPTY_LIST, "", // xformsControl.getValue(pipelineContext), 1)); // } itemset.visit( contentHandler, new ItemsetListener() { private int optgroupCount = 0; public void startLevel(ContentHandler contentHandler, Item item) throws SAXException {} public void endLevel(ContentHandler contentHandler) throws SAXException { if (optgroupCount-- > 0) { // End xhtml:optgroup contentHandler.endElement( XMLConstants.XHTML_NAMESPACE_URI, "optgroup", optGroupQName); } } public void startItem(ContentHandler contentHandler, Item item, boolean first) throws SAXException { final String label = item.getLabel(); final String value = item.getValue(); if (value == null) { final String itemClasses = getItemClasses(item, null); final AttributesImpl optGroupAttributes = getAttributes(XMLUtils.EMPTY_ATTRIBUTES, itemClasses, null); if (label != null) optGroupAttributes.addAttribute( "", "label", "label", ContentHandlerHelper.CDATA, label); // Start xhtml:optgroup contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "optgroup", optGroupQName, optGroupAttributes); optgroupCount++; } else { handleItemCompact( contentHandler, optionQName, xformsSelect1Control, isMultiple, item); } } public void endItem(ContentHandler contentHandler) throws SAXException {} }); } } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "select", selectQName); } } } else { // Read-only mode final String spanQName = XMLUtils.buildQName(xhtmlPrefix, "span"); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "span", spanQName, containerAttributes); if (!handlerContext.isTemplate()) { final String value = (xformsSelect1Control == null || xformsSelect1Control.getValue(pipelineContext) == null) ? "" : xformsSelect1Control.getValue(pipelineContext); final StringBuilder sb = new StringBuilder(); if (itemset != null) { int selectedFound = 0; for (final Item currentItem : itemset.toList()) { if (XFormsItemUtils.isSelected(isMultiple, value, currentItem.getValue())) { if (selectedFound > 0) sb.append(" - "); sb.append(currentItem.getLabel()); selectedFound++; } } } if (sb.length() > 0) { final String result = sb.toString(); contentHandler.characters(result.toCharArray(), 0, result.length()); } } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "span", spanQName); } }
private void outputFull( String uri, String localname, Attributes attributes, String effectiveId, XFormsValueControl xformsControl, Itemset itemset, boolean isMultiple, boolean isBooleanInput) throws SAXException { final ContentHandler contentHandler = handlerContext.getController().getOutput(); final AttributesImpl containerAttributes = getContainerAttributes(uri, localname, attributes, effectiveId, xformsControl, !isFull); final String xhtmlPrefix = handlerContext.findXHTMLPrefix(); final String fullItemType = isMultiple ? "checkbox" : "radio"; // In noscript mode, use <fieldset> // TODO: This really hasn't much to do with noscript; should we always use fieldset, or make // this an // option? Benefit of limiting to noscript is that then no JS change is needed final String containingElementName = handlerContext.isNoScript() ? "fieldset" : "span"; final String containingElementQName = XMLUtils.buildQName(xhtmlPrefix, containingElementName); final String spanQName = XMLUtils.buildQName(xhtmlPrefix, "span"); { // Old layout always output container <span>/<fieldset>, and in new layout we only put it for // select/select1 final boolean outputContainerElement = !isBooleanInput || !handlerContext.isSpanHTMLLayout(); if (outputContainerElement) contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, containingElementName, containingElementQName, containerAttributes); { if (handlerContext.isNoScript()) { // Output <legend> final String legendName = "legend"; final String legendQName = XMLUtils.buildQName(xhtmlPrefix, legendName); reusableAttributes.clear(); // TODO: handle other attributes? xforms-disabled? reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, "xforms-label"); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, legendName, legendQName, reusableAttributes); if (xformsControl != null) { final boolean mustOutputHTMLFragment = xformsControl.isHTMLLabel(pipelineContext); outputLabelText( contentHandler, xformsControl, xformsControl.getLabel(pipelineContext), xhtmlPrefix, mustOutputHTMLFragment); } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, legendName, legendQName); } if (itemset != null) { int itemIndex = 0; for (Iterator<Item> i = itemset.toList().iterator(); i.hasNext(); itemIndex++) { final Item item = i.next(); final String itemEffectiveId = getItemId(effectiveId, Integer.toString(itemIndex)); handleItemFull( pipelineContext, handlerContext, contentHandler, reusableAttributes, attributes, xhtmlPrefix, spanQName, containingDocument, xformsControl, effectiveId, itemEffectiveId, isMultiple, fullItemType, item, itemIndex == 0); } } } if (outputContainerElement) contentHandler.endElement( XMLConstants.XHTML_NAMESPACE_URI, containingElementName, containingElementQName); } // NOTE: Templates for full items are output globally in XHTMLBodyHandler }
public static void handleItemFull( PipelineContext pipelineContext, HandlerContext handlerContext, ContentHandler contentHandler, AttributesImpl reusableAttributes, Attributes attributes, String xhtmlPrefix, String spanQName, XFormsContainingDocument containingDocument, XFormsValueControl xformsControl, String effectiveId, String itemEffectiveId, boolean isMultiple, String type, Item item, boolean isFirst) throws SAXException { // Whether this is selected boolean isSelected = isSelected(pipelineContext, handlerContext, xformsControl, isMultiple, item); // xhtml:span enclosing input and label final String itemClasses = getItemClasses(item, isSelected ? "xforms-selected" : "xforms-deselected"); final AttributesImpl spanAttributes = getAttributes(reusableAttributes, XMLUtils.EMPTY_ATTRIBUTES, itemClasses, null); // Add item attributes to span addItemAttributes(item, spanAttributes); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "span", spanQName, spanAttributes); { { // xhtml:input final String inputQName = XMLUtils.buildQName(xhtmlPrefix, "input"); reusableAttributes.clear(); reusableAttributes.addAttribute( "", "id", "id", ContentHandlerHelper.CDATA, itemEffectiveId); reusableAttributes.addAttribute("", "type", "type", ContentHandlerHelper.CDATA, type); // Get group name from selection control if possible, otherwise use effective id final String name = (!isMultiple && xformsControl instanceof XFormsSelect1Control) ? ((XFormsSelect1Control) xformsControl).getGroupName() : effectiveId; reusableAttributes.addAttribute("", "name", "name", ContentHandlerHelper.CDATA, name); reusableAttributes.addAttribute( "", "value", "value", ContentHandlerHelper.CDATA, item.getExternalValue(pipelineContext)); if (!handlerContext.isTemplate() && xformsControl != null) { if (isSelected) { reusableAttributes.addAttribute( "", "checked", "checked", ContentHandlerHelper.CDATA, "checked"); } if (isFirst) { // Handle accessibility attributes handleAccessibilityAttributes(attributes, reusableAttributes); } } handleDisabledAttribute(reusableAttributes, containingDocument, xformsControl); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "input", inputQName, reusableAttributes); contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "input", inputQName); } // We don't output the label within <input></input>, because XHTML won't display it. final String label = item.getLabel(); if (label != null) { // allow null label to tell not to output the <label> element at all reusableAttributes.clear(); outputLabelFor( handlerContext, reusableAttributes, itemEffectiveId, itemEffectiveId, LHHAC.LABEL, "label", label, false, false); // TODO: may be HTML for full appearance } } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "span", spanQName); }
public static void outputResponseDocument( final PipelineContext pipelineContext, final ExternalContext externalContext, final IndentedLogger indentedLogger, final SAXStore annotatedDocument, final XFormsContainingDocument containingDocument, final XMLReceiver xmlReceiver) throws SAXException, IOException { final List<XFormsContainingDocument.Load> loads = containingDocument.getLoadsToRun(); if (containingDocument.isGotSubmissionReplaceAll()) { // 1. Got a submission with replace="all" // NOP: Response already sent out by a submission // TODO: modify XFormsModelSubmission accordingly indentedLogger.logDebug("", "handling response for submission with replace=\"all\""); } else if (loads != null && loads.size() > 0) { // 2. Got at least one xforms:load // Send redirect out // Get first load only final XFormsContainingDocument.Load load = loads.get(0); // Send redirect final String redirectResource = load.getResource(); indentedLogger.logDebug( "", "handling redirect response for xforms:load", "url", redirectResource); // Set isNoRewrite to true, because the resource is either a relative path or already contains // the servlet context externalContext.getResponse().sendRedirect(redirectResource, null, false, false, true); // Still send out a null document to signal that no further processing must take place XMLUtils.streamNullDocument(xmlReceiver); } else { // 3. Regular case: produce an XHTML document out final ElementHandlerController controller = new ElementHandlerController(); // Register handlers on controller (the other handlers are registered by the body handler) { controller.registerHandler( XHTMLHeadHandler.class.getName(), XMLConstants.XHTML_NAMESPACE_URI, "head"); controller.registerHandler( XHTMLBodyHandler.class.getName(), XMLConstants.XHTML_NAMESPACE_URI, "body"); // Register a handler for AVTs on HTML elements final boolean hostLanguageAVTs = XFormsProperties .isHostLanguageAVTs(); // TODO: this should be obtained per document, but we only // know about this in the extractor if (hostLanguageAVTs) { controller.registerHandler( XXFormsAttributeHandler.class.getName(), XFormsConstants.XXFORMS_NAMESPACE_URI, "attribute"); controller.registerHandler( XHTMLElementHandler.class.getName(), XMLConstants.XHTML_NAMESPACE_URI); } // Swallow XForms elements that are unknown controller.registerHandler( NullHandler.class.getName(), XFormsConstants.XFORMS_NAMESPACE_URI); controller.registerHandler( NullHandler.class.getName(), XFormsConstants.XXFORMS_NAMESPACE_URI); controller.registerHandler(NullHandler.class.getName(), XFormsConstants.XBL_NAMESPACE_URI); } // Set final output controller.setOutput(new DeferredXMLReceiverImpl(xmlReceiver)); // Set handler context controller.setElementHandlerContext( new HandlerContext( controller, pipelineContext, containingDocument, externalContext, null)); // Process the entire input annotatedDocument.replay( new ExceptionWrapperXMLReceiver(controller, "converting XHTML+XForms document to XHTML")); } containingDocument.afterInitialResponse(); }