/** * @param containingHtmlElement the name of the HTML element containing el. If the HTML element is * contained inside a template construct then this name may differ from el's immediate parent. */ private void inspectElement(JobEnvelope source, Element el, ElKey containingHtmlElement) { ElKey elKey = ElKey.forElement(el); // Recurse early so that ihtml:dynamic elements have been parsed before we // process the attributes element list. for (Node child : Nodes.childrenOf(el)) { inspect(source, child, elKey); } // For each attribute allowed on this element type, ensure that // (1) If it is not specified, and its default value is not allowed, then // it is added with a known safe value. // (2) Its value is rewritten as appropriate. // We don't have to worry about disallowed attributes since those will // not be present in scriptsPerNode. The TemplateSanitizer should have // stripped those out. The TemplateSanitizer should also have stripped out // disallowed elements. if (!htmlSchema.isElementAllowed(elKey)) { return; } HTML.Element elInfo = htmlSchema.lookupElement(elKey); List<HTML.Attribute> attrs = elInfo.getAttributes(); if (attrs != null) { for (HTML.Attribute a : attrs) { AttribKey attrKey = a.getKey(); if (!htmlSchema.isAttributeAllowed(attrKey)) { continue; } Attr attr = null; String aUri = attrKey.ns.uri; String aName = attrKey.localName; Attr unsafe = el.getAttributeNodeNS(aUri, aName); if (unsafe != null && a.getValueCriterion().accept(unsafe.getValue())) { attr = unsafe; } else if ((a.getDefaultValue() != null && !a.getValueCriterion().accept(a.getDefaultValue())) || !a.isOptional()) { attr = el.getOwnerDocument().createAttributeNS(aUri, aName); String safeValue; if (a.getType() == HTML.Attribute.Type.URI) { safeValue = "" + Nodes.getFilePositionFor(el).source().getUri(); } else { safeValue = a.getSafeValue(); } if (safeValue == null) { mq.addMessage( IhtmlMessageType.MISSING_ATTRIB, Nodes.getFilePositionFor(el), elKey, attrKey); continue; } attr.setNodeValue(safeValue); el.setAttributeNodeNS(attr); } if (attr != null) { inspectHtmlAttribute(source, attr, a); } } } scriptsPerNode.put(el, null); }
private void inspectFragment( JobEnvelope source, DocumentFragment f, ElKey containingHtmlElement) { scriptsPerNode.put(f, null); for (Node child : Nodes.childrenOf(f)) { // We know that top level text nodes in a document fragment // are not significant if they are just newlines and indentation. // This decreases output size significantly. if (isWhitespaceOnlyTextNode(child)) { continue; } inspect(source, child, containingHtmlElement); } }
private void runTest(String goldenIhtml, String inputIhtml, Message... expectedMessages) throws Exception { Element ihtmlRoot = new DomParser( DomParser.makeTokenQueue( FilePosition.startOfFile(is), new StringReader(inputIhtml), true, false), true, mq) .parseDocument(); new IhtmlSanityChecker(mq).check(ihtmlRoot); for (Message msg : expectedMessages) { assertMessage( true, msg.getMessageType(), msg.getMessageLevel(), msg.getMessageParts().toArray(new MessagePart[0])); } assertMessagesLessSevereThan(MessageLevel.WARNING); String checkedIhtml = Nodes.render(ihtmlRoot, MarkupRenderMode.XML); assertEquals(goldenIhtml, checkedIhtml); }