| /******************************************************************************* |
| * Copyright (c) 2005, 2016 IBM Corporation and Others |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Kentarou FUKUDA - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.actf.visualization.internal.engines.blind.html.util; |
| |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.Stack; |
| |
| import org.eclipse.actf.visualization.engines.blind.ParamBlind; |
| import org.eclipse.actf.visualization.engines.blind.TextChecker; |
| import org.eclipse.actf.visualization.engines.blind.html.IBlindProblem; |
| import org.eclipse.actf.visualization.engines.voicebrowser.IPacket; |
| import org.eclipse.actf.visualization.engines.voicebrowser.IPacketCollection; |
| import org.eclipse.actf.visualization.eval.html.HtmlTagUtil; |
| import org.eclipse.actf.visualization.eval.problem.IProblemItem; |
| import org.eclipse.actf.visualization.internal.engines.blind.html.BlindProblem; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| |
| public class NodeInfoCreator { |
| |
| private static final String HEADING_TAGS = "h1|h2|h3|h4|h5|h6"; //$NON-NLS-1$ |
| |
| private static final String LIST_TAGS = "ul|ol|dl"; //$NON-NLS-1$ |
| |
| private static final String LANDMARK_TAGS = "nav|main|article|aside"; //$NON-NLS-1$ |
| |
| private static final String HEADER_FOOTER_TAGS = "header|footer"; //$NON-NLS-1$ |
| |
| private static final Set<String> BLOCK_TAG_SET = HtmlTagUtil.getBlockElementSet(); |
| |
| private VisualizeMapDataImpl mapData; |
| |
| private TextChecker textChecker; |
| |
| private List<IProblemItem> problems; |
| |
| private Set<String> invisibleIdSet; |
| |
| private TextCounter textCounter; |
| |
| /** |
| * |
| */ |
| public NodeInfoCreator(VisualizeMapDataImpl mapData, TextChecker textChecker, List<IProblemItem> problems, |
| Set<String> invisibleIdSet, ParamBlind paramBlind) { |
| this.mapData = mapData; |
| this.textChecker = textChecker; |
| this.problems = problems; |
| this.invisibleIdSet = invisibleIdSet; |
| textCounter = new TextCounter(paramBlind.iLanguage); |
| } |
| |
| @SuppressWarnings("nls") |
| private String removePeriod(String targetS, Node targetNode) { |
| if (targetNode != null) { |
| String nodeS = targetNode.getNodeName(); |
| if (nodeS.equals("img") || nodeS.equals("applet")) {// AREA? |
| if (targetS.endsWith(".]")) { |
| targetS = targetS.substring(0, targetS.lastIndexOf(".]")) + "]"; |
| } |
| } |
| } |
| return targetS; |
| } |
| |
| @SuppressWarnings("nls") |
| private boolean isIdRequiredInput(Element el) { |
| String tagName = el.getNodeName(); |
| if (tagName.equals("select")) { |
| return true; |
| } else if (tagName.equals("textarea")) { |
| return true; |
| } else if (tagName.equals("input")) { |
| String type = el.getAttribute("type").toLowerCase(); |
| if ((type.length() == 0) | type.equals("text") | type.equals("textarea") | type.equals("radio") |
| | type.equals("checkbox")) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @SuppressWarnings("nls") |
| // TODO |
| public void prepareNodeInfo(IPacketCollection pc) { |
| // node - nodeInfo |
| int size = 0; |
| |
| if (pc == null) { |
| return; |
| } else { |
| size = pc.size(); |
| } |
| |
| int totalWords = 0; |
| int lineNumber = 0; |
| int previousLineNumber = 0; |
| |
| String prevText = null; |
| IPacket prevPacket = null; |
| |
| for (int it = 0; it < size; it++) { |
| IPacket p = pc.get(it); |
| |
| Node node = p.getNode(); |
| if (node.getNodeType() == Node.ELEMENT_NODE) { |
| String nodeName = node.getNodeName(); |
| if (nodeName.equals("option")) { |
| Element el = (Element) node; |
| Node attrNode = el.getAttributeNode("selected"); |
| if (attrNode == null) |
| continue; // !!!! |
| } else if (nodeName.equals("area")) { |
| continue; // !!!! |
| } else if (nodeName.equals("map")) { |
| continue; // !!!! |
| } |
| } |
| |
| String curText = p.getText(); |
| if ((curText != null) && (curText.length() > 0)) { |
| |
| // TODO consider ALT text ('['+alt+']') |
| // check inappropritate text |
| |
| if (textChecker.isSeparatedJapaneseChars(curText)) { |
| String nodeName = p.getNode().getNodeName(); |
| if (!nodeName.matches("img|input|area")) {// already checked |
| BlindProblem prob = new BlindProblem(IBlindProblem.WRONG_TEXT, curText); |
| prob.setNode(p.getNode()); |
| prob.setTargetNode(mapData.getOrigNode(p.getNode())); |
| problems.add(prob); |
| } |
| } |
| |
| // check redundant texts |
| if ((prevPacket != null) |
| && (p.getContext().isInsideAnchor() == prevPacket.getContext().isInsideAnchor())) { |
| Node curNode = p.getNode(); |
| Node prevNode = prevPacket.getNode(); |
| |
| if (!curNode.getNodeName().equals("input")) { |
| // TODO temporal solution to avoid label problem of |
| // JWAT. |
| // JWAT count same text twice, if an input has a label. |
| |
| if (textChecker.isRedundantText(prevText, curText)) { |
| if (!HtmlTagUtil.hasAncestor(curNode, "noscript") |
| && !HtmlTagUtil.hasAncestor(prevNode, "noscript")) { |
| // remove "." from error (comment from JIM) |
| prevText = removePeriod(prevText, prevNode); |
| curText = removePeriod(curText, curNode); |
| |
| BlindProblem prob = new BlindProblem(IBlindProblem.REDUNDANT_ALT, |
| "\"" + prevText + "\" & \"" + curText + "\""); |
| prob.setNode(prevNode); |
| prob.addNode(curNode); |
| |
| // TODO insideAnchor -> check same target? |
| if (prevNode.getNodeName().equals("img")) { |
| prob.setTargetNode(mapData.getOrigNode(prevNode)); |
| prob.setTargetStringForExport(prevText); |
| problems.add(prob); |
| } else if (curNode.getNodeName().equals("img")) { |
| prob.setTargetNode(mapData.getOrigNode(curNode)); |
| prob.setTargetStringForExport(curText); |
| problems.add(prob); |
| } else { |
| // TODO ALERT_REDUNDANT_TEXT |
| } |
| } |
| } |
| } |
| } |
| |
| prevText = curText; |
| prevPacket = p; |
| } |
| |
| VisualizationNodeInfo already = mapData.getNodeInfo(p.getNode()); |
| |
| if (already != null) { /* end tag? */ |
| // TODO ?? |
| } else { |
| VisualizationNodeInfo info = new VisualizationNodeInfo(); |
| info.setPacket(p); |
| // info.setNode(p.getNode()); |
| int words = textCounter.getWordCount(p.getText()); |
| |
| // take into acount structurization |
| boolean isVisible = true; |
| |
| Node curNode = p.getNode(); |
| while (curNode != null) { |
| String nodeName = curNode.getNodeName(); |
| if (curNode.getNodeType() == Node.ELEMENT_NODE) { |
| Element tmpE = (Element) curNode; |
| if (tmpE.hasAttribute("accesskey")) { |
| info.setAccesskey(true); |
| } |
| if (invisibleIdSet.contains(tmpE.getAttribute("id"))) { |
| info.setInvisible(true); |
| isVisible = false; |
| // System.out.println(tmpE.getAttribute("id")); |
| } |
| } |
| |
| if (nodeName.matches(HEADING_TAGS)) { |
| info.setHeading(true); |
| info.appendComment("Heading: " + nodeName + "."); |
| } else if (nodeName.equals("th")) { |
| info.setTableHeader(true); |
| info.appendComment("Table header."); |
| } else if (nodeName.equals("label")) { |
| info.setLabel(true); |
| info.appendComment("Label for '" + ((Element) curNode).getAttribute("for") + "'. "); |
| } else if (nodeName.contains("caption")){ |
| info.setCaption(true); |
| info.appendComment(curNode.getNodeName()); |
| } |
| |
| if (nodeName.equals("body")) { |
| break; |
| } |
| curNode = curNode.getParentNode(); |
| } |
| |
| if (isVisible) { |
| info.setWords(words); |
| info.setTotalWords(totalWords); |
| info.setOrgTotalWords(totalWords); |
| totalWords += words; |
| if (words > 0) { |
| lineNumber++; |
| } |
| info.setTotalLines(previousLineNumber); |
| info.setOrgTotalLines(previousLineNumber); |
| info.setLines(lineNumber - previousLineNumber); |
| |
| previousLineNumber = lineNumber; |
| } else { |
| // invisible |
| info.setWords(0); |
| info.setTotalWords(totalWords); |
| info.setOrgTotalWords(totalWords); |
| info.setTotalLines(previousLineNumber); |
| info.setOrgTotalLines(previousLineNumber); |
| info.setLines(0); |
| } |
| info.setPacketId(it); |
| |
| mapData.addNodeInfoMapping(p.getNode(), info); |
| } |
| } |
| } |
| |
| @SuppressWarnings("nls") |
| public void createAdditionalNodeInfo(Document doc) { |
| // create elementList |
| // set node info ID |
| // List nodeList = new ArrayList(1024); |
| int origTotalWords = 0; |
| int origTotalLines = 0; |
| |
| Map<String, String> mapTextMap = VisualizeMapUtil.createMapTextMap(doc); |
| |
| NodeList bodyNl = doc.getElementsByTagName("body"); |
| if (bodyNl.getLength() > 0) { |
| if (bodyNl.getLength() > 1) { |
| System.out.println("multiple body"); |
| } |
| Element bodyEl = (Element) bodyNl.item(0); |
| |
| // TODO traversel |
| |
| if (bodyEl.hasChildNodes()) { |
| |
| Stack<Node> stack = new Stack<Node>(); |
| stack.push(bodyEl); |
| Node curNode = bodyEl.getFirstChild(); |
| VisualizationNodeInfo lastInfo = null; |
| int counter = 0; |
| // int tableCount = 0; |
| int listCount = 0; |
| |
| while ((curNode != null) && (stack.size() > 0)) { |
| String curNodeName = curNode.getNodeName(); |
| VisualizationNodeInfo curInfo = mapData.getNodeInfo(curNode); |
| |
| if (curNode.getNodeType() == Node.TEXT_NODE) { |
| // add text nodes involved in the PacketCollection. |
| if (curInfo != null) { |
| curInfo.setId(counter); |
| mapData.addNodeInfoIntoList(curInfo); |
| counter++; |
| lastInfo = curInfo; |
| } |
| } else if (curNode.getNodeType() == Node.ELEMENT_NODE) { |
| if (curInfo != null) { |
| curInfo.setId(counter); |
| mapData.addNodeInfoIntoList(curInfo); |
| counter++; |
| lastInfo = curInfo; |
| } else { |
| // create NodeInfo for nodes not in packet. |
| // ("b", "img" without alt, etc.) |
| try { |
| curInfo = new VisualizationNodeInfo(lastInfo); |
| curInfo.setWords(0); |
| curInfo.setLines(0); |
| curInfo.setId(counter); |
| curInfo.setNode(curNode); |
| counter++; |
| mapData.addNodeInfoIntoList(curInfo); |
| |
| // TODO check invisible |
| |
| mapData.addNodeInfoMapping(curNode, curInfo); |
| |
| } catch (NullPointerException npe) { |
| // no previous info error |
| npe.printStackTrace(); |
| } |
| } |
| |
| if (curNodeName.equals("img")) { |
| // TODO handle invisible map |
| String map = ((Element) curNode).getAttribute("usemap"); |
| if ((map != null) && (map.length() > 0)) { |
| int words = curInfo.getWords(); |
| String curText = mapTextMap.get(map.toLowerCase().substring(1)); |
| int add = textCounter.getWordCount(curText); |
| curInfo.setWords(words + add); |
| curInfo.setLines(curInfo.getLines() + 1); |
| } |
| } |
| |
| if (curNodeName.matches(LANDMARK_TAGS)) { |
| curInfo.setLandmark(true); |
| curInfo.appendComment("Landmark: " + curNodeName + "."); |
| // System.out.println("Landmark: " + curNodeName + |
| // "."); |
| } else if (curNodeName.matches(HEADER_FOOTER_TAGS)) { |
| if (!HtmlTagUtil.hasAncestor(curNode, "article") |
| && !HtmlTagUtil.hasAncestor(curNode, "section")) { |
| curInfo.setLandmark(true); |
| curInfo.appendComment( |
| "Landmark: " + curNodeName + " without ancestor article/section."); |
| // System.out.println("Landmark: " + curNodeName |
| // + " without ancestor article/section."); |
| } |
| } |
| |
| } |
| |
| if (curInfo != null) { |
| curInfo.setTotalWords(origTotalWords); |
| curInfo.setOrgTotalWords(origTotalWords); |
| curInfo.setTotalLines(origTotalLines); |
| curInfo.setOrgTotalLines(origTotalLines); |
| origTotalWords = origTotalWords + curInfo.getWords(); |
| origTotalLines = origTotalLines + curInfo.getLines(); |
| |
| if (listCount > 0) { |
| curInfo.setSequence(true); |
| } |
| if (BLOCK_TAG_SET.contains(curNodeName)) { |
| curInfo.setBlockElement(true); |
| } |
| |
| if (curNode.getNodeType() == Node.ELEMENT_NODE) { |
| if (isIdRequiredInput((Element) curNode)) { |
| curInfo.setIdRequiredInput(true); |
| curInfo.appendComment( |
| "Input with id, '" + ((Element) curNode).getAttribute("id") + "'. "); |
| } |
| } |
| |
| mapData.addNodeIdMapping(curInfo.getNode(), new Integer(curInfo.getId())); |
| |
| } |
| |
| boolean isListTag = curNodeName.matches(LIST_TAGS); |
| if (curNode.hasChildNodes()) { |
| // if (curNodeName.equals("table")) { |
| // tableCount++; |
| // } |
| if (isListTag) { |
| listCount++; |
| } |
| |
| stack.push(curNode); |
| curNode = curNode.getFirstChild(); |
| } else if (curNode.getNextSibling() != null) { |
| // if (curNodeName.equals("table")) { |
| // tableCount--; |
| // } |
| if (isListTag) { |
| listCount--; |
| } |
| curNode = curNode.getNextSibling(); |
| } else { |
| // if (curNodeName.equals("table")) { |
| // tableCount--; |
| // } |
| if (isListTag) { |
| listCount--; |
| } |
| |
| curNode = null; |
| while ((curNode == null) && (stack.size() > 0)) { |
| curNode = stack.pop(); |
| curNodeName = curNode.getNodeName(); |
| // if (curNodeName.equals("table")) { |
| // tableCount--; |
| // } |
| if (isListTag) { |
| listCount--; |
| } |
| curNode = curNode.getNextSibling(); |
| } |
| } |
| } |
| // System.out.println(tableCount); |
| } |
| } |
| } |
| } |