2008-12-02 130 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