首先,让我们稍微平整一下场地。我稍微清理了您的代码以获得编译起点。我删除了不必要的代码并通过我对它应该做什么的最佳猜测来修复该方法。我对其进行了一点概括,使其接受一个tagName
参数。它仍然是相同的代码并且犯了同样的错误,但现在它可以编译了(为了方便起见,使用 Java 7 功能,如果需要,将其切换回 Java 6)。为此,我还将其拆分try-catch
为多个块:
public Map<String, String> getElementAttributesByTagName(String tagName) {
Document document;
try (InputStream input = new FileInputStream(sourcePage)) {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
document = docBuilder.parse(input);
} catch (IOException | ParserConfigurationException | SAXException e) {
throw new RuntimeException(e);
}
NodeList attributeList;
try {
XPath xPath = XPathFactory.newInstance().newXPath();
attributeList = (NodeList)xPath.evaluate("//descendant::" + tagName + "[1]/@*", document, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
}
Map<String, String> tagInfo = new HashMap<>();
for (int i = 0; i < attributeList.getLength(); i++) {
Attr attribute = (Attr)attributeList.item(i);
tagInfo.put(attribute.getName(), attribute.getValue());
}
return tagInfo;
}
当针对上面的示例代码运行时,它会返回:
{height=48, alt=Funny face, width=48, src=funny.gif}
解决方案取决于您的预期输出。你要么想要
- 仅获取其中一个
<img>
元素的属性(例如,第一个元素)
- 获取所有
<img>
元素及其属性的列表
对于第一个解决方案,将 XPath 表达式更改为
//descendant::img[1]/@*
或者
//descendant::" + tagName + "[1]/@*
与tagName
参数。请注意,这与在这种特殊情况下返回相同元素的情况不同。//img[1]/@*
以这种方式更改时,该方法返回:
{height=42, alt=Smiley face, width=42, src=smiley.gif}
这是第一个<img>
元素的正确返回属性。
请注意,您甚至不必为此类工作使用 XPath 表达式。这是一个非 XPath 版本:
public Map<String, String> getElementAttributesByTagNameNoXPath(String tagName) {
Document document;
try (InputStream input = new FileInputStream(sourcePage)) {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
document = docBuilder.parse(input);
} catch (IOException | ParserConfigurationException | SAXException e) {
throw new RuntimeException(e);
}
Node node = document.getElementsByTagName(tagName).item(0);
NamedNodeMap attributeMap = node.getAttributes();
Map<String, String> tagInfo = new HashMap<>();
for (int i = 0; i < attributeMap.getLength(); i++) {
Node attribute = attributeMap.item(i);
tagInfo.put(attribute.getNodeName(), attribute.getNodeValue());
}
return tagInfo;
}
第二种解决方案需要稍微改变一下。我们想要返回<img>
文档中所有元素的属性。多个元素意味着我们将使用 aList
来保存多个Map<String, String>
实例,其中每个Map
代表一个<img>
元素。
一个完整的 XPath 版本,以防您确实需要一些复杂的 XPath 表达式:
public List<Map<String, String>> getElementsAttributesByTagName(String tagName) {
Document document;
try (InputStream input = new FileInputStream(sourcePage)) {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
document = docBuilder.parse(input);
} catch (IOException | ParserConfigurationException | SAXException e) {
throw new RuntimeException(e);
}
NodeList nodeList;
try {
XPath xPath = XPathFactory.newInstance().newXPath();
nodeList = (NodeList)xPath.evaluate("//" + tagName, document, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
}
List<Map<String, String>> tagInfoList = new ArrayList<>();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
NamedNodeMap attributeMap = node.getAttributes();
Map<String, String> tagInfo = new HashMap<>();
for (int j = 0; j < attributeMap.getLength(); j++) {
Node attribute = attributeMap.item(j);
tagInfo.put(attribute.getNodeName(), attribute.getNodeValue());
}
tagInfoList.add(tagInfo);
}
return tagInfoList;
}
要摆脱 XPath 部分,您可以简单地将其切换为单行:
NodeList nodeList = document.getElementsByTagName(tagName);
这两个版本,当您使用参数对上面的测试用例运行时"img"
,返回:(为清晰起见格式化)
[ {height=42, alt=Smiley face, width=42, src=smiley.gif},
{height=45, alt=Sad face, width=45, src=sad.gif },
{height=48, alt=Funny face, width=48, src=funny.gif } ]
这是所有<img>
元素的正确列表。