簡體   English   中英

XML中進行流過濾的最佳Java方法?

[英]best java approach for stream filtering in XML?

我希望將XML文件作為輸入並輸出相同的XML,但基於匹配某些節點特征的屬性和文本的某些搜索/替換操作除外。

最好的一般方法是什么,那里有教程嗎?

DOM已淘汰,因為我無法保證能夠將整個內容保存在內存中。

我不介意使用SAX或StAX,除了我希望默認行為是通過無操作濾鏡。 我曾經用StAX做過類似的事情,這很痛苦,不適用於名稱空間,而且我不確定是否已經包括了我需要處理的所有情況。

我認為XSLT不起作用(但不確定),因為它是聲明性的,在確定要在輸出中發出什么文本/屬性時,我需要進行一些過程計算。

(人為的示例:

假設我正在尋找所有XPath為/group/item/@number節點,並希望將number屬性評估為整數,請使用public List<Integer> factorize(int i)方法對其進行public List<Integer> factorize(int i) ,將因子列表轉換為一個以空格分隔的字符串,並將屬性factors添加到相應的/group/item節點?

輸入:

<group name="beatles"><item name="paul" number="64"></group>
<group name="rolling stones"><item name="mick" number="19"></group>
<group name="who"><item name="roger" number="515"></group>

預期輸出:

<group name="beatles"><item name="paul" number="64" factors="2 2 2 2 2 2"></group>
<group name="rolling stones"><item name="mick" number="19" factors="19"></group>
<group name="who"><item name="roger" number="515" factors="103 5"></group>

更新:我使StAX XMLEventReader / Writer方法可以輕松工作,但是並沒有保留某些對我的應用程序很重要的格式設置怪癖。 (我猜想,保存/加載XML的程序不能使用有效的XML文件。> :( argh。)是否有一種處理XML的方法,可以最大限度地減少輸入和輸出之間的文本差異?(至少在字符數據方面)。 )

XSLT似乎適合您的工作。 考慮將XSLT與過程擴展一起使用。

如果您真的無法將整個文檔保存在內存中,那么Saxon是您唯一的XSLT選擇。 您可能需要執行的任何計算都可以在XSLT中完成,但是如果沒有,編寫您自己的擴展功能並不是太困難。

我發現Apache Digester對於基於規則的XML解析有很大幫助。

更新:如果您正在關注過濾和輸出,請在Developerworks上查看與同一問題有關的這組文章。 特別相關的是 2、34部分 摘要:使用SAX,XMLFilter和XMLWriter。

盡管我認為從技術上講,這很適合XSLT,但我總是發現很難調試復雜的轉換。 YMMV :-)

進一步更新: XMLWriter從此處可用。 我不知道您使用SAX的特別困難是什么。 我創建了一個包含以下內容的文件groups.xml

<groups>
<group name="beatles"><item name="paul" number="64"/></group>
<group name="rolling stones"><item name="mick" number="19"/></group>
<group name="who"><item name="roger" number="515"/></group>
</groups>

請注意,我必須進行一些更改以使其格式正確的XML。 然后,我打開了這個簡單的Jython腳本groups.py ,以說明如何解決您的問題:

import java.io
import org.xml.sax.helpers
import sys

sys.path.append("xml-writer.jar")
import com.megginson.sax

def get_factors(n):
    return "factors for %s" % n

class MyFilter(org.xml.sax.helpers.XMLFilterImpl):
    def startElement(self, uri, localName, qName, attrs):
        if qName == "item":
            newAttrs = org.xml.sax.helpers.AttributesImpl(attrs)
            n = attrs.length
            for i in range(n):
                name = attrs.getLocalName(i)
                if name == "number":
                    newAttrs.addAttribute("", "factors", "factors",
                                          "CDATA",
                                          get_factors(attrs.getValue(i)))
            attrs = newAttrs
        #call superclass method...
        org.xml.sax.helpers.XMLFilterImpl.startElement(self, uri, localName,
                                                       qName, attrs)

source = org.xml.sax.InputSource(java.io.FileInputStream("groups.xml"))
reader = org.xml.sax.helpers.XMLReaderFactory.createXMLReader()
filter = MyFilter(reader)
writer = com.megginson.sax.XMLWriter(filter,
                                     java.io.FileWriter("output.xml"))
writer.parse(source)

顯然,我已經模擬了因子查找功能,因為我相信您的示例純粹是說明性的。 該腳本讀取groups.xml ,應用過濾器,然后輸出到output.xml 讓我們運行它:

$ jython groups.py
$ cat output.xml
<?xml version="1.0" standalone="yes"?>

<groups>
<group name="beatles"><item name="paul" number="64" factors="factors for 64"></item></group>
<group name="rolling stones"><item name="mick" number="19" factors="factors for 19"></item></group>
<group name="who"><item name="roger" number="515" factors="factors for 515"></item></group>
</groups>

任務完成? 當然,您需要將此代碼轉錄為Java。

StAX應該適合您。 輸入到輸出的管道超級簡單; 您只需編寫從XMLEventReader獲得的XMLEvent到XMLEventWriter。

XMLEventFactory EVT_FACTORY;
XMLEventReader reader;
XMLEventWriter writer;

QName numberQName = new QName("number");
QName factorsQName = new QName("factors");
while(reader.hasNext()) {
  XMLEvent e = reader.nextEvent();
  if(e.isAttribute() && ((Attribute)e).getName().equals(numberQName)) {
     String v = ((Attribute)e).getValue();
     String factors = factorize(Integer.parseInt(v));
     XMLEvent factorsAttr = EVT_FACTORY.createAttribute(factorsQName, factors);
     writer.add(factorsAttr);
  }
  // pass through
  writers.add(e);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM