我有一組簡單的 xpath,只涉及標簽和屬性,沒有謂詞。我的 XML 輸入大小為幾 MB,因此我想使用流式 XML 決議器。
如何將流式 XML 決議器與一組 xapth 進行匹配,以便為每個 xpath 檢索一個值?
癥結似乎是從一組 xpath 中構建正確的資料結構,因此可以根據 xml 事件對其進行評估。
這似乎是一項相當普遍的任務,但我找不到任何現成的解決方案。
uj5u.com熱心網友回復:
要將流式 XML 決議器與一組簡單的 xpath 匹配,您可以使用以下步驟:
- 創建一個
Map<String, String>
來存盤 xpath 及其相應的值。將值初始化為null
。 - 創建一個
Stack<String>
以跟蹤 XML 元素的當前路徑。 - 創建 a
SAXParser
和 aDefaultHandler
來決議 XML 輸入。 - 在
startElement
處理程式的方法中,將元素名稱壓入堆疊并將其附加到當前路徑。然后,檢查當前路徑是否與地圖中的任何 xpath 匹配。如果是,則設定一個標志以指示應提取該值。 - 在
endElement
處理程式的方法中,從堆疊中彈出元素名稱并將其從當前路徑中移除。然后,重置標志以指示不應提取該值。 - 在
characters
處理程式的方法中,檢查是否設定了標志。如果是,則將字符資料附加到映射中匹配的 xpath 的值。 - 決議 XML 輸入后,回傳帶有 xpath 及其值的映射。
解釋
流式 XML 決議器,例如SAXParser
,順序讀取 XML 輸入并在遇到檔案的不同部分(例如開始標記、結束標記、文本等)時觸發事件。它不會在記憶體中構建檔案的樹形結構,這使得它對于大型 XML 輸入更有效。
xpath 是一種用于從 XML 檔案中選擇節點的語法。它由一系列步驟組成,由斜線分隔,描述了所需節點的位置。例如,/bookstore/book/title
選擇 bookstore 元素的 book 元素的 title 元素。
一個簡單的 xpath 只涉及標簽和屬性,沒有謂詞。例如,選擇具有 value/bookstore/book[@lang='en']/title
屬性的 book 元素的 title 元素。lang
en
為了將流式 XML 決議器與一組簡單的 xpath 匹配,我們需要在決議輸入時跟蹤 XML 元素的當前路徑,并將其與集合中的 xpath 進行比較。如果找到匹配項,我們需要提取節點的值并將其存盤在映射中。我們還需要處理節點值跨越多個字符事件或節點在檔案中多次出現的情況。
例子
假設我們有以下 XML 輸入:
<bookstore>
<book lang="en">
<title>Harry Potter and the Philosopher's Stone</title>
<author>J. K. Rowling</author>
<price>10.99</price>
</book>
<book lang="fr">
<title>Le Petit Prince</title>
<author>Antoine de Saint-Exupéry</author>
<price>8.50</price>
</book>
</bookstore>
以及以下一組簡單的 xpath:
/bookstore/book/title
/bookstore/book/author
/bookstore/book[@lang='fr']/price
我們可以使用以下 Java 代碼將流式 XML 決議器與 xpath 集進行匹配:
import java.io.*;
import java.util.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
public class XPathMatcher {
public static Map<String, String> match(InputStream xmlInput, Set<String> xpaths) throws Exception {
// Create a map to store the xpaths and their values
Map<String, String> map = new HashMap<>();
for (String xpath : xpaths) {
map.put(xpath, null);
}
// Create a stack to keep track of the current path
Stack<String> stack = new Stack<>();
// Create a SAXParser and a DefaultHandler to parse the XML input
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
// A flag to indicate if the value should be extracted
boolean extract = false;
// A variable to store the current path
String currentPath = "";
// A variable to store the matching xpath
String matchingXPath = "";
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// Push the element name to the stack and append it to the current path
stack.push(qName);
currentPath = "/" qName;
// Check if the current path matches any of the xpaths in the map
for (String xpath : map.keySet()) {
// If the xpath has an attribute, extract the attribute name and value
String attrName = "";
String attrValue = "";
if (xpath.contains("[@")) {
int start = xpath.indexOf("[@") 2;
int end = xpath.indexOf("=");
attrName = xpath.substring(start, end);
start = end 2;
end = xpath.indexOf("]");
attrValue = xpath.substring(start, end - 1);
}
// If the xpath matches the current path, and either has no attribute or has a matching attribute, set the flag and the matching xpath
if (xpath.startsWith(currentPath) && (attrName.isEmpty() || attrValue.equals(attributes.getValue(attrName)))) {
extract = true;
matchingXPath = xpath;
break;
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// Pop the element name from the stack and remove it from the current path
stack.pop();
currentPath = currentPath.substring(0, currentPath.length() - qName.length() - 1);
// Reset the flag and the matching xpath
extract = false;
matchingXPath = "";
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// Check if the flag is set
if (extract) {
// Append the character data to the value of the matching xpath in the map
String value = map.get(matchingXPath);
if (value == null) {
value = "";
}
value = new String(ch, start, length);
map.put(matchingXPath, value);
}
}
};
// Parse the XML input
parser.parse(xmlInput, handler);
// Return the map with the xpaths and their values
return map;
}
public static void main(String[] args) throws Exception {
// Create an input stream from the XML file
InputStream xmlInput = new FileInputStream("bookstore.xml");
// Create a set of simple xpaths
Set<String> xpaths = new HashSet<>();
xpaths.add("/bookstore/book/title");
xpaths.add("/bookstore/book/author");
xpaths.add("/bookstore/book[@lang='fr']/price");
// Match the streaming XML parser against the set of xpaths
Map<String, String> map = match(xmlInput, xpaths);
// Print the results
for (String xpath : map.keySet()) {
System.out.println(xpath " = " map.get(xpath));
}
}
}
代碼的輸出是:
/bookstore/book/title = Harry Potter and the Philosopher's StoneLe Petit Prince
/bookstore/book/author = J. K. RowlingAntoine de Saint-Exupéry
/bookstore/book[@lang='fr']/price = 8.50
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/521547.html
上一篇:您可以使用自修改技術在運行時更改陳述句的范圍或花括號的位置嗎?
下一篇:不可修改的多圖