2008-12-02 62 views
1

鑑於下面的XML片段,我需要爲DataElements下的每個子項獲取名稱/值對列表。 XPath或XML解析器不能用於我無法控制的原因,所以我正在使用正則表達式。在Java中使用REGEX解析XML

<?xml version="1.0"?> 
<StandardDataObject xmlns="myns"> 
    <DataElements> 
    <EmpStatus>2.0</EmpStatus> 
    <Expenditure>95465.00</Expenditure> 
    <StaffType>11.A</StaffType> 
    <Industry>13</Industry> 
    </DataElements> 
    <InteractionElements> 
    <TargetCenter>92f4-MPA</TargetCenter> 
    <Trace>7.19879</Trace> 
    </InteractionElements> 
</StandardDataObject> 

我需要的輸出是: [{EmpStatus:2.0},{支出:95465.00},{StaffType:11.A},{行業:13}]

標籤下DataElements名稱是動態的,所以不能在正則表達式中直接表達。標記名稱TargetCenter和Trace是靜態的,可能在正則表達式中,但是如果有一種方法可以避免硬編碼,那將是更可取的。

"<([A-Za-z0-9]+?)>([A-Za-z0-9.]*?)</" 

這是我構造正則表達式,它有,它錯誤地包括{跟蹤:719879}的問題的結果。依賴於XML中的新行或其他任何明顯的格式化不是一種選擇。

下面是我使用的Java代碼的近似值:

private static final Pattern PATTERN_1 = Pattern.compile(..REGEX..); 
private List<DataElement> listDataElements(CharSequence cs) { 
    List<DataElement> list = new ArrayList<DataElement>(); 
    Matcher matcher = PATTERN_1.matcher(cs); 
    while (matcher.find()) { 
     list.add(new DataElement(matcher.group(1), matcher.group(2))); 
    } 
    return list; 
} 

如何將我的正則表達式改爲只包括數據元素,而忽略其他人呢?

+5

你爲什麼不使用適當的XML解析器?它會(a)更簡單,並且(b)不涉及調試正則表達式。 – 2008-12-02 20:10:24

+0

是否有使用Regex而不是僅使用XPath和XML DOM的原因? – EBGreen 2008-12-02 20:10:37

+0

呃......交叉帖子。 :) – EBGreen 2008-12-02 20:11:12

回答

11

這應該在Java中工作,如果您可以假設在DataElements標籤之間,所有東西都具有表單值。即沒有屬性,也沒有嵌套元素。

Pattern regex = Pattern.compile("<DataElements>(.*?)</DataElements>", Pattern.DOTALL); 
Matcher matcher = regex.matcher(subjectString); 
Pattern regex2 = Pattern.compile("<([^<>]+)>([^<>]+)</\\1>"); 
if (matcher.find()) { 
    String DataElements = matcher.group(1); 
    Matcher matcher2 = regex2.matcher(DataElements); 
    while (matcher2.find()) { 
     list.add(new DataElement(matcher2.group(1), matcher2.group(2))); 
    } 
} 
1

是否有任何理由你沒有使用正確的XML解析器,而不是正則表達式的?這對於合適的圖書館來說是微不足道的。

+0

我的懷疑是,無論採取什麼方法,這都是微不足道的,我無法在這種情況下使用XML解析器。 – Mocky 2008-12-02 20:43:25

3

改爲使用XPath!

2

你真的應該使用這個XML庫。如果你不得不使用RE,爲什麼不在兩個階段做? DataElements>.*?</DataElements那麼你現在擁有什麼。

1

對不起,給你另一個「不要使用正則表達式」的答案,但認真。請使用Commons-Digester,JAXP(與Java 5+捆綁)或JAXB(與Java 6+捆綁),因爲它可以讓您免受一船傷害。

50

XML不是常規語言。您不能使用正則表達式解析它。當你得到嵌套標籤時,你認爲可以工作的表達式會破壞,然後當你修復它時,會破壞XML註釋,然後是CDATA部分,然後是處理器指令,然後命名空間......它無法工作,使用XML解析器。

1

你應該聽取每個人的意見。輕量級的解析器是一個壞主意。但是,如果你真的很努力的話,你應該能夠調整你的代碼,以排除DataElements標籤之外的標籤。

private static final Pattern PATTERN_1 = Pattern.compile(..REGEX..); 
private static final String START_TAG = "<DataElements>"; 
private static final String END_TAG = "</DataElements>"; 
private List<DataElement> listDataElements(String input) { 
    String cs = input.substring(input.indexOf(START_TAG) + START_TAG.length(), input.indexOf(END_TAG); 
    List<DataElement> list = new ArrayList<DataElement>(); 
    Matcher matcher = PATTERN_1.matcher(cs); 
    while (matcher.find()) { 
     list.add(new DataElement(matcher.group(1), matcher.group(2))); 
    } 
    return list; 
} 

如果dataelements標記不存在,這會失敗。

再一次,這是一個壞主意,你可能會在未來的某段時間以bug報告的形式重新訪問這段代碼。

0

嘗試通過屬性文件解析Reg Ex並創建模式對象。我在通過xml bean注入Reg Ex時遇到了同樣的問題。例如: - 我需要解析Reg Ex'(。)(D [0-9] {7} .D [0-9] {9} .D [AZ] {3} [0-9 ] {4})(。)'在Spring中注入。但它沒有奏效。一旦嘗試使用它在其工作的Java類中硬編碼的相同Reg Ex。模式模式= Pattern.compile(「(。)(D [0-9] {7} .D [0-9] {9} .D [AZ] {2} [0-9] {4 })()「)。 Matcher matcher = pattern.matcher(file.getName()。trim());

Next I tried to load that Reg Ex via property file while injecting it. It worked fine. 

    p:remoteDirectory="${rawDailyReport.remote.download.dir}" 
    p:localDirectory="${rawDailyReport.local.valid.dir}" 
    p:redEx="${rawDailyReport.download.regex}" 

而在屬性文件中,屬性定義如下。

rawDailyReport.download.regex =(。)(D [0-9] {7} \。D [0-9] {9} \。D [AZ] {2} [0-9] { 4})(。

這是因爲帶有佔位符的值是通過org.springframework.beans.factory.config.PropertyPlaceholderConfigurer加載的,它在內部處理這些xml敏感字符。

感謝, Amith