AddIfDirective.java mistakes processing instructions for elements

Open
#440 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@Inf1mum is already working on this.

Since Nov 14, 2026.

  • #441 by @Inf1mum — open

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
35/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
java
Domain
tooling

Research direction

Start in src/main/java/org/xembly/AddIfDirective.java, lines 53-57, where the child scan compares getNodeName() without checking getNodeType(). Fix the match to require Node.ELEMENT_NODE and confirm the existing creation path then adds the missing element, as shown by AttrDirective.exec() casting the node to Element. Done means the snippet in src/test/java/org/xembly (add a regression case whose PI target equals the requested element name) yields <root><?item data?><item id="1"/></root>. Note pull request #441 is already open on this, so coordinate before starting.

Written by the indexing model from the issue text.

Description

ADDIF 'item' reuses <?item data?> instead of creating an item element. A following ATTR then throws ClassCastException because its cursor contains a processing instruction.

For example:

new Xembler(
    new Directives()
        .add("root")
        .pi("item", "data")
        .addIf("item")
        .attr("id", "1")
).dom();

This should produce <root><?item data?><item id="1"/></root>. Instead, ADDIF leaves the element absent and Element.class.cast(node) in AttrDirective.exec() receives the processing instruction.

In src/main/java/org/xembly/AddIfDirective.java, lines 53–57, the lookup compares names without checking the node type:

if (kids.item(idx).getNodeName().equals(this.name.raw())) {
    target = kids.item(idx);
    break;
}

A processing instruction's node name is its target, so it can match any requested element name. Restrict the match to element nodes:

if (kids.item(idx).getNodeType() == Node.ELEMENT_NODE
    && kids.item(idx).getNodeName().equals(this.name.raw())) {
    target = kids.item(idx);
    break;
}

This lets the existing creation path add the missing element while preserving the processing instruction. Add a regression case with a PI whose target equals the requested element name; the existing PI coverage uses a different target.

Dominant language
Java
Stars
248
Forks
33
Avg merge
17h 59m
Merged PRs (30d)
46

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from yegor256/xembly

All issues in yegor256/xembly

Similar issues

More Java issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.