草庐IT

java - Apache Digester XML 解析器注释和复合模型

coder 2024-07-01 原文

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

<?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. 决策/CriterionGroups/CriterionGroup/标准/标准

这是我的对象模型:

@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/CriterionDecision/CriterionGroups/CriterionGroup/Criteria/Criterion 仍然是 NULL。如何配置我的模型并更改注释以便能够解析具有两个不同位置的 CriterionNode

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

最佳答案

我能看到的两个问题:

首先,您发布的代码仅匹配作为决策的直接子项的标准。即您匹配了“Decision/Criteria/Criterion”,但没有匹配“Decision/CriterionGroups/CriterionGroup/Criteria/Criterion”,因此永远不会创建更深层次的元素。最简单的解决方案就是使用通配符:

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

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

第二个问题是 CriterionNodeSetNext 规则,这个有点棘手。切入正题,我认为这段代码应该适合您:

@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);
  }

}

之所以可行,是因为注释构建下一个规则集的方式。

A set next rule需要三样东西:

  1. 一个模式。
  2. 方法名称。
  3. 参数类型。

所以这个注释试图实现的是:

digester.addSetNext("*/Criteria/Criterion", "addCriterionNode", "CriterionNode")

请注意,此规则中的任何地方均未提及拥有的 DecisionNodeCriterionGroupNode

方法名称和参数类型很简单 - 它们直接来自带注释的方法 - 但模式不太清楚。注释处理查看与参数匹配的注释来推断模式,因此在这种情况下,参数是一个 CriterionNode,并且具有匹配的 ObjectCreate 注释“*/Criteria/Criterion”,因此它创建了所需的规则。

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

关于 Digester 注释的注释

我将在此添加关于 Digester 注释的标准免责声明:我个人不喜欢它们并且从不使用它们,原因有二:

  1. 一个更笼统:我认为注解应该只用在 他们说的是类本身,而不是类的使用方式,但这只是我个人对过度使用注释的看法。
  2. 特别是 Digester 注释:它们只能满足极其简单的情况,甚至像这样简单的事情也会导致上述问题。

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

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 Bean 约定(该属性必须是小驼峰 - 因此 getName 和 setName 定义属性“name”而不是“Name”)。因此,如果您的 XML 使用小写实体,例如“名称”和“描述”,那么您可以使用更短的:

forPattern("*/Criterion/Name").setBeanProperty();
forPattern("*/Criterion/Description").setBeanProperty();

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

干杯

关于java - Apache Digester XML 解析器注释和复合模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41331929/

有关java - Apache Digester XML 解析器注释和复合模型的更多相关文章

  1. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  5. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  6. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  7. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  8. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  9. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  10. ruby-on-rails - 如何将验证与模型分开 - 2

    我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:

随机推荐