RSS Feed 中 <description> 包含嵌套標籤(<image>、<text>、CDATA 等),SAX 解析器按事件流處理,難以一次性獲取完整內部 XML 片段。DOM 解析器將整個文檔加載為樹,便於直接提取子樹。
public List<String> parseDescriptions(InputStream inputStream) throws Exception {
List<String> descriptions = new ArrayList<>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // 支援命名空間
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(inputStream);
// 獲取所有 <item> 節點
NodeList items = doc.getElementsByTagName("item");
for (int i = 0; i < items.getLength(); i++) {
Element item = (Element) items.item(i);
// 獲取第一個 <description> 子元素
NodeList descNodes = item.getElementsByTagName("description");
if (descNodes.getLength() > 0) {
Element descElement = (Element) descNodes.item(0);
// 方案 A:獲取文本內容(包含 CDATA 解碼後的純文本)
String textContent = descElement.getTextContent();
// 方案 B:獲取內部原始 XML(包含嵌套標籤結構)
String innerXml = getInnerXml(descElement);
descriptions.add(innerXml); // 或 textContent
}
}
return descriptions;
}
// 輔助方法:將 Node 及其子樹序列化為 XML 字串
private String getInnerXml(Node node) {
try {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StringWriter writer = new StringWriter();
// 僅輸出子節點,不包含自身標籤
for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
transformer.transform(new DOMSource(child), new StreamResult(writer));
}
return writer.toString();
} catch (TransformerException e) {
throw new RuntimeException(e);
}
}
DocumentBuilder.parse(InputStream) 直接解析流,無需先讀成字串。getElementsByTagName("description") 遞歸查找所有後代,若 description 只在 item 直屬,可用 item.getElementsByTagName("description")。getTextContent() 返回純文本(CDATA 已解碼、標籤移除);getInnerXml() 保留結構。XmlPullParser 流式讀取至目標標籤再切換 DOM 解析該片段。
// 在 DefaultHandler 中
boolean inDescription = false;
StringBuilder descBuffer = new StringBuilder();
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) {
if ("description".equals(qName)) inDescription = true;
}
@Override
public void characters(char[] ch, int start, int length) {
if (inDescription) descBuffer.append(ch, start, length);
}
@Override
public void endElement(String uri, String localName, String qName) {
if ("description".equals(qName)) {
inDescription = false;
String fullDesc = descBuffer.toString(); // 含 CDATA 內容
descBuffer.setLength(0);
}
}
SAX 需手動維護狀態,處理嵌套標籤極其繁瑣,**強烈推薦 DOM 或 XmlPullParser**。
RSS description 含豐富結構時,DOM 解析器配合 Transformer 序列化內部 XML 是最直接可靠的方法。大文件場景可混合使用 Pull 解析定位片段再 DOM 解析。