你如何忽略Apache Digester的元素?

时间:2015-07-24 11:39:51

标签: xml apache-commons-digester

如何设置消化符规则以忽略具有特定属性值的元素?例如,给定下面的XML和digester规则,如何告诉它忽略名称等于“Alex”的参数?

XML:

<input-parameters>
    <parameter>
        <name><![CDATA[Steve]]></name>
        <description><![CDATA[Footballer]]></description>
    </parameter>
    <parameter>
        <name><![CDATA[Adam]]></name>
        <description><![CDATA[Author]]></description>
    </parameter>
    <parameter>
        <name><![CDATA[Lynda]]></name>
        <description><![CDATA[Blacksmith]]></description>
    </parameter>
    <parameter> <!--I want to ignore this whole parameter element.-->
        <name><![CDATA[Alex]]></name>
        <description><![CDATA[Showjumper]]></description>
    </parameter>            
</input-parameters>

当前的XML规则:

<pattern value="input-parameters">
    <object-create-rule classname="java.util.HashSet"/>
    <set-next-rule methodname="addParameters"/>

    <pattern value="parameter">
        <object-create-rule classname="com.foo"/>
        <set-next-rule methodname="add"/>
        <bean-property-setter-rule pattern="name" propertyname="name" />
        <bean-property-setter-rule pattern="description" propertyname="description" />
    </pattern>
</pattern>

1 个答案:

答案 0 :(得分:0)

我不认为Digester原生支持这种做法,但我可以建议一些可能有助于你到达那里的选择。

最简单的方法是使用自定义HashSet实施,拒绝您不喜欢的名称:

public class MyHashSet extends HashSet<Parameter> {
  @Override
  public boolean add(Parameter param) {
    if (param != null && "Alex".equals(param.getName())) {
      return false;
    }
    return super.add(param);
  }
}

然后在规则中使用此代替标准HashSet

<pattern value="input-parameters">
    <object-create-rule classname="com.foo.MyHashSet"/>
    <set-next-rule methodname="addParameters"/>
    ...
</pattern>

我从这种方法中可以看到的主要缺点是你在结果对象中留下了自定义哈希集实现,所以如果你以后尝试添加一个名为=&#34的参数; Alex&#34;直接从代码中再次被拒绝;这可能是也可能不是问题。

稍微复杂一点的方法是使用自定义实现切换标准SetNextRule,该实现在添加参数之前检查名称。标准SetNextRule会在事件结束时触发,因此以下规则可以解决问题:

public class SetNextParamRule extends SetNextRule {

  public SetNextParamRule() {
    super("add");
  }

  @Override
  public void end(String namespace, String name) throws Exception {
    Parameter param = (Parameter)getChild();
    if (!"Alex".equals(param.getName())) {
      super.end(namespace, name);
    }
  }
}

这种方法的一个问题是我无法看到使用XML配置添加自定义规则的方法(我很少使用XML配置,因此这里可能是错误的),因此您需要使用代码配置:

final Rule setNextParamRule = new SetNextParamRule();

RulesModule rules = new AbstractRulesModule() {
  @Override
  public void configure() {
    forPattern("input-parameters")
        .createObject().ofType(HashSet.class)
        .then().setNext("addParameters");
    forPattern("input-parameters/parameter")
        .createObject().ofType(Parameter.class)
        .then().addRule(setNextParamRule);
    forPattern("input-parameters/parameter/name").setBeanProperty();
    forPattern("input-parameters/parameter/description").setBeanProperty();
  }
};

DigesterLoader loader = DigesterLoader.newLoader(rules);
Digester digester = loader.newDigester();

然而,这样做的一个优点是您可能会从单独的来源提供要忽略的名称列表:

import com.google.common.collect.ImmutableSet;

final Set<String> skipNames = ImmutableSet.of("Alex", "Adam");

final Rule setNextParamRule = new SetNextRule("add") {
  @Override
  public void end(String namespace, String name) throws Exception {
    Parameter param = (Parameter)getChild();
    if (!skipNames.contains(param.getName())) {
      super.end(namespace, name);
    }
  }
};

// rest as above

希望其中一些有用。