首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Apache解析器注释和复合模型

Apache解析器注释和复合模型
EN

Stack Overflow用户
提问于 2016-12-26 13:20:58
回答 1查看 239关注 0票数 2

我有以下XML文档,我将使用Apache解析器(通过Digester注释)将其解析为一个对象模型:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<Decision>
    <Name>Antivirus software for Windows</Name>
    <Description>Description 1</Description>
    <Url>http://yahoo.com</Url>
    <ImageUrl>http://yahoo.com/img.jpg</ImageUrl>
    <CriterionGroups>
        <CriterionGroup>
            <Name>Windows</Name>
            <Description>Description 1</Description>
            <Criteria>
                <Criterion>
                    <Name>Heuristics</Name>
                    <Description>Description 1</Description>
                </Criterion>
            </Criteria>
        </CriterionGroup>
    </CriterionGroups>
    <Criteria>
        <Criterion>
            <Name>On-demand scan</Name>
            <Description>Description 1</Description>
        </Criterion>
    </Criteria>
    <CharacteristicGroups>
        <CharacteristicGroup>
            <Name>Windows</Name>
            <Description>Description 1</Description>
            <Characteristics>
                <Characteristic>
                    <Name>Country of origin</Name>
                    <Description>Description 1</Description>
                    <ValueType>String</ValueType>
                    <VisualMode>SelectBox</VisualMode>
                    <Sortable>true</Sortable>
                    <Options>
                        <Option>
                            <Value>Shareware</Value>
                            <Description>Description 1</Description>
                        </Option>
                    </Options>
                </Characteristic>
            </Characteristics>
        </CharacteristicGroup>
    </CharacteristicGroups>
    <Characteristics>
        <Characteristic>
            <Name>License</Name>
            <Description>Description 1</Description>
            <ValueType>Integer</ValueType>
            <VisualMode>Slider</VisualMode>
            <Sortable>false</Sortable>
        </Characteristic>
    </Characteristics>
    <Decisions>
        <Decision>
            <Name>Avast Free Antivirus</Name>
            <Description>Description 1</Description>
            <Url>http://google.com</Url>
            <ImageUrl>http://google.com/img.jpg</ImageUrl>
            <Votes>
                <Vote>
                    <CriterionName>On-demand scan</CriterionName>
                    <Weight>4.3</Weight>
                </Vote>
                <Vote>
                    <CriterionName>Heuristics</CriterionName>
                    <CriterionName>On-demand scan</CriterionName>
                    <Weight>4.3</Weight>
                    <Description>Description 1</Description>
                </Vote>
            </Votes>
            <Values>
                <Value>
                    <CharacteristicName>License</CharacteristicName>
                    <Value>Proprietary</Value>
                    <Description>Description 1</Description>
                </Value>
            </Values>
        </Decision>
    </Decisions>
</Decision>

从这个XML中可以看到,有两个由两条不同路径组成的Criterion节点:

  1. 决定/标准/标准
  2. Decision/CriterionGroups/CriterionGroup/Criteria/Criterion

这是我的对象模型:

代码语言:javascript
复制
@ObjectCreate(pattern = "Decision")
public class DecisionNode {

    @BeanPropertySetter(pattern = "Decision/Name")
    private String name;
    @BeanPropertySetter(pattern = "Decision/Description")
    private String description;
    @BeanPropertySetter(pattern = "Decision/Url")
    private String url;
    @BeanPropertySetter(pattern = "Decision/ImageUrl")
    private String imageUrl;

    private List<CriterionGroupNode> criterionGroupNodes = new ArrayList<>();
    private List<CriterionNode> criterionNodes = new ArrayList<>();
    private List<CharacteristicGroupNode> characteristicGroupNodes = new ArrayList<>();
    private List<CharacteristicNode> characteristicNodes = new ArrayList<>();
    private List<DecisionNode> decisionNodes = new ArrayList<>();
    private List<VoteNode> voteNodes = new ArrayList<>();
    private List<ValueNode> valueNodes = new ArrayList<>();

    ....

    @SetNext
    public boolean addCriterionGroupNode(CriterionGroupNode criterionGroupNode) {
        return criterionGroupNodes.add(criterionGroupNode);
    }

    ....

}

@ObjectCreate(pattern = "Decision/CriterionGroups/CriterionGroup")
public class CriterionGroupNode {

    @BeanPropertySetter(pattern = "Decision/CriterionGroups/CriterionGroup/Name")
    private String name;
    @BeanPropertySetter(pattern = "Decision/CriterionGroups/CriterionGroup/Description")
    private String description;

    private List<CriterionNode> criterionNodes = new ArrayList<>();

    ....

    @SetNext
    public boolean addCriterionNode(CriterionNode criterionNode) {
        return criterionNodes.add(criterionNode);
    }

    ....

}

@ObjectCreate(pattern = "Decision/Criteria/Criterion")
public class CriterionNode {

    @BeanPropertySetter(pattern = "Decision/Criteria/Criterion/Name")
    private String name;
    @BeanPropertySetter(pattern = "Decision/Criteria/Criterion/Description")
    private String description;

    public CriterionNode() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

}

现在我只能解析Decision/Criteria/Criterion,但是Decision/CriterionGroups/CriterionGroup/Criteria/Criterion仍然是NULL。如何配置我的模型和更改注释,以便能够用两个不同的位置解析CriterionNode

另外,我不明白为什么解析器通过Decision/Criteria/Criterion找到两个Criterion节点而不是一个节点

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-12-30 03:00:04

我能看到两个问题:

首先,您所发布的代码仅与决策的直接子级标准相匹配。也就是说,您已经匹配了“决策/标准/标准”,而不是"Decision/CriterionGroups/CriterionGroup/Criteria/Criterion",,因此永远不会创建更深层次的元素。对此,最简单的解决方案就是使用通配符:

代码语言:javascript
复制
@ObjectCreate(pattern = "*/Criteria/Criterion")
public static class CriterionNode {

  @BeanPropertySetter(pattern = "*/Criteria/Criterion/Name")
  private String name;
  @BeanPropertySetter(pattern = "*/Criteria/Criterion/Description")
  private String description;

第二个问题是关于SetNext规则的CriterionNode,这个问题有点棘手。首先,我认为这段代码应该适用于您:

代码语言:javascript
复制
@ObjectCreate(pattern = "Decision")
public class DecisionNode {

  ...

  @SetNext
  public boolean addCriterionNode(CriterionNode criterionNode) {
    return criterionNodes.add(criterionNode);
  }

}

@ObjectCreate(pattern = "Decision/CriterionGroups/CriterionGroup")
public class CriterionGroupNode {

  ...

  // no SetNext rule on this method
  public boolean addCriterionNode(CriterionNode criterionNode) {
    return criterionNodes.add(criterionNode);
  }

}

这样做的原因是注释构建下一个规则集的方式。

设置下一个规则需要三件事:

  1. 一个图案。
  2. 一个方法名。
  3. 参数类型。

因此,这个注释所要达到的目标相当于:

代码语言:javascript
复制
digester.addSetNext("*/Criteria/Criterion", "addCriterionNode", "CriterionNode")

请注意,在此规则的任何地方都没有提到拥有的DecisionNodeCriterionGroupNode

方法名称和参数类型很简单--它们直接来自注释的方法--但是模式不太清楚。注释处理会查看与参数匹配的注释,从而推断模式,因此在本例中,参数是一个CriterionNode,并且有一个匹配的ObjectCreate注释,用于“*/ObjectCreate/Criteria”,因此它创建了所需的规则。

您不需要CriterionGroupNode类中的第二个CriterionGroupNode的原因是它会复制完全相同的处理,因此将添加一个重复的规则。

--关于蒸发器注释的一个注记

我将将我的标准免责声明添加到有关消化器注释的内容中:就我个人而言,我不喜欢它们,而且从来不使用它们有两个原因:

  1. 一个是比较普遍的:我认为注释只应该在他们谈论类本身的时候使用,而不是关于它是如何使用的,但这只是我个人对过度使用注释的看法。
  2. 特别是消化注释:它们只能满足极端简单的情况,甚至是像上面这样容易引起问题的东西。

我发现基于规则的配置对于快速映射来说是最简单的,如果需要扩展的话,也是最强大的配置。在这种情况下,类似于:

代码语言:javascript
复制
RulesModule rules = new AbstractRulesModule() {
  @Override
  public void configure() {

    forPattern("Decision")
        .createObject().ofType(DecisionNode.class);

    forPattern("Decision/Name").addRule(new BeanPropertySetterRule("name"));
    forPattern("Decision/Description").addRule(new BeanPropertySetterRule("description"));
    forPattern("Decision/Url").addRule(new BeanPropertySetterRule("url"));
    forPattern("Decision/ImageUrl").addRule(new BeanPropertySetterRule("imageUrl"));

    forPattern("Decision/CriterionGroups/CriterionGroup")
        .createObject().ofType(CriterionGroupNode.class)
        .then().setNext("addCriterionGroupNode");

    forPattern("Decision/CriterionGroups/CriterionGroup/Name").addRule(new BeanPropertySetterRule("name"));
    forPattern("Decision/CriterionGroups/CriterionGroup/Description").addRule(new BeanPropertySetterRule("description"));

    forPattern("*/Criterion")
        .createObject().ofType(CriterionNode.class)
        .then().setNext("addCriterionNode");

    forPattern("*/Criterion/Name").addRule(new BeanPropertySetterRule("name"));
    forPattern("*/Criterion/Description").addRule(new BeanPropertySetterRule("description"));

  }
};

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

DecisionNode dn = digester.parse(...);

请注意,只需要扩展版本的BeanPropertySetterRule,因为您的XML实体不遵循Java约定(属性必须是较低的-camel-因此getName和setName定义了属性"name“而不是"Name")。因此,如果您的XML使用小写实体,如"name“和"description”,那么您可以使用更短的:

代码语言:javascript
复制
forPattern("*/Criterion/Name").setBeanProperty();
forPattern("*/Criterion/Description").setBeanProperty();

您的XML完全没有理由遵循Java约定--如果您想知道为什么需要扩展版本,我只是指出这一点。

干杯

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41331929

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档