• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

devonfw / IDEasy / 13944696202

19 Mar 2025 10:48AM UTC coverage: 67.644% (-0.01%) from 67.657%
13944696202

Pull #1146

github

web-flow
Merge 255542aee into 2ef884351
Pull Request #1146: Fix/1008 improve upgrade settings

3043 of 4923 branches covered (61.81%)

Branch coverage included in aggregate %.

7843 of 11170 relevant lines covered (70.21%)

3.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.37
cli/src/main/java/com/devonfw/tools/ide/merge/xmlmerger/matcher/IdComputer.java
1
package com.devonfw.tools.ide.merge.xmlmerger.matcher;
2

3
import javax.xml.xpath.XPath;
4
import javax.xml.xpath.XPathConstants;
5
import javax.xml.xpath.XPathExpression;
6
import javax.xml.xpath.XPathExpressionException;
7
import javax.xml.xpath.XPathFactory;
8

9
import org.w3c.dom.Element;
10
import org.w3c.dom.NodeList;
11

12
import com.devonfw.tools.ide.context.IdeContext;
13
import com.devonfw.tools.ide.merge.xmlmerger.XmlMergeSupport;
14

15
/**
16
 * The IdComputer class is responsible for building XPath expressions and evaluating those expressions to match elements in a target document.
17
 */
18
public class IdComputer {
19

20
  /** The value of merge:id that is used to evaluate the xpath expression. */
21
  private final String id;
22

23
  private final IdeContext context;
24

25
  private static final XPathFactory xPathFactory = XPathFactory.newInstance();
3✔
26

27
  /**
28
   * The constructor.
29
   *
30
   * @param id the {@link #getId() merge ID}.
31
   */
32
  public IdComputer(String id, IdeContext context) {
33

34
    super();
2✔
35
    this.id = id;
3✔
36
    this.context = context;
3✔
37
  }
1✔
38

39
  /**
40
   * @return the value of "merge:id" attribute what is an {@link XPath} expression.
41
   * @see XmlMergeSupport#getMergeId(Element)
42
   */
43
  public String getId() {
44

45
    return this.id;
×
46
  }
47

48
  /**
49
   * Evaluates the XPath expression for the given merge element in the target element.
50
   *
51
   * @param templateElement the template {@link Element} for which to build the {@link XPath} expression.
52
   * @param workspaceElement the workspace {@link Element} in which to evaluate the {@link XPath} expression.
53
   * @return the matched Element if found, or {@code null} if not found
54
   */
55
  public Element evaluateExpression(Element templateElement, Element workspaceElement) {
56
    XPath xpath = xPathFactory.newXPath();
3✔
57
    xpath.setNamespaceContext(new NamespaceContextFromElement(templateElement));
6✔
58
    String xpathExpr = buildXPathExpression(templateElement);
4✔
59
    try {
60
      XPathExpression xpathExpression = xpath.compile(xpathExpr);
4✔
61
      NodeList nodeList = (NodeList) xpathExpression.evaluate(workspaceElement, XPathConstants.NODESET);
6✔
62
      int length = nodeList.getLength();
3✔
63
      if (length == 1) {
3✔
64
        return (Element) nodeList.item(0);
5✔
65
      } else if (length == 0) {
2!
66
        return null;
2✔
67
      } else {
68
        this.context.warning(length + " matches found for XPath " + xpathExpr + " in workspace XML at " + XmlMergeSupport.getXPath(workspaceElement, true));
×
69
        return (Element) nodeList.item(0);
×
70
      }
71
    } catch (XPathExpressionException e) {
×
72
      throw new IllegalStateException("Failed to compile XPath expression " + xpath, e);
×
73
    }
74
  }
75

76
  /**
77
   * Builds the XPath expression for the given merge element based on the {@link #getId()} merge:id} value.
78
   *
79
   * @param element the {@link Element} for which to build the XPath expression
80
   * @return the XPath expression as a {@link String}.
81
   */
82
  private String buildXPathExpression(Element element) {
83

84
    String namespaceURI = element.getNamespaceURI();
3✔
85
    String localName = element.getLocalName();
3✔
86
    if (localName == null) {
2!
87
      localName = element.getTagName();
×
88
    }
89
    String prefix = element.getPrefix();
3✔
90

91
    StringBuilder xpathBuilder = new StringBuilder(localName.length());
6✔
92
    if ((prefix != null) && !prefix.isEmpty()) {
5!
93
      xpathBuilder.append(prefix).append(":");
6✔
94
    }
95
    xpathBuilder.append(localName);
4✔
96
    if (this.id.startsWith("@")) {
5✔
97
      String attributeName = this.id.substring(1);
5✔
98
      String attributeValue = element.getAttribute(attributeName);
4✔
99
      xpathBuilder.append('[').append(this.id).append("='").append(XmlMergeSupport.escapeSingleQuotes(attributeValue)).append("']");
14✔
100
    } else if (this.id.equals(XmlMergeSupport.XPATH_ELEMENT_NAME)) {
6✔
101
      xpathBuilder.append("[local-name()='").append(localName).append("']");
8✔
102
      if ((namespaceURI != null) && !namespaceURI.isEmpty()) {
2!
103
        xpathBuilder.append(" and namespace-uri()='").append(namespaceURI).append('\'');
×
104
      }
105
    } else if (this.id.equals(XmlMergeSupport.XPATH_ELEMENT_TEXT)) {
5✔
106
      String textContent = element.getTextContent();
3✔
107
      xpathBuilder.append("[text()='").append(XmlMergeSupport.escapeSingleQuotes(textContent)).append("']");
9✔
108
    } else { // custom xpath like ../element[@attr='value']
1✔
109
      return this.id;
3✔
110
    }
111
    return xpathBuilder.toString();
3✔
112
  }
113

114
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc