3

次の 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、2 つの異なるパスに 2 つのノードがあります。

  1. 決定/基準/基準
  2. Decision/CriterionGroups/CriterionGroup/Criteria/Criterion

これは私のオブジェクトモデルです:

@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. CriterionNode2 つの異なる場所で解析できるようにするには、モデルを構成して注釈を変更する方法を教えてください。

Criterionまた、パーサーが次の方法で 1 つのノードではなく2 つのノードを検出する理由がわかりませんDecision/Criteria/Criterion

ここに画像の説明を入力

4

1 に答える 1

2

私が見ることができる2つの問題:

まず、投稿したコードは、決定の直接の子である基準にのみ一致します。つまり、「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;

2 番目の問題は のSetNextルールにありCriterionNode、これは少しトリッキーです。追いつくために、私はこのコードがあなたのために働くはずだと思います:

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

}

これが機能する理由は、アノテーションが set next ルールを構築する方法にあります。

set next ルールには次の3 つのものが必要です。

  1. パターン。
  2. メソッド名。
  3. パラメータ タイプ。

したがって、この注釈が達成しようとしているのは、次のものと同等です。

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

DecisionNodeこのルールでは、所有も所有もCriterionGroupNode言及されていないことに注意してください。

メソッド名とパラメーターの型は簡単です (注釈付きのメソッドから直接取得するだけです) が、パターンはあまり明確ではありません。注釈処理は、パラメーターに一致する注釈を調べてパターンを推測します。この場合、パラメーターは であり、 「*/Criteria/Criterion」にCriterionNode一致する注釈があるため、目的のルールが作成されます。ObjectCreate

SetNextRuleクラスに1 秒も必要ない理由はCriterionGroupNode、まったく同じ処理が複製されるため、重複するルールが追加されるためです。

ダイジェスターの注釈に関する注意

Digester アノテーションに関して、これに私の標準的な免責事項を追加します。

  1. 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 の規則に従うべき理由はまったくありません。なぜ拡張バージョンが必要なのか疑問に思っている方のために、私はこれを指摘しているだけです。

乾杯

于 2016-12-30T03:00:04.853 に答える