XNode.java

  1. /*
  2.  *    Copyright 2009-2021 the original author or authors.
  3.  *
  4.  *    Licensed under the Apache License, Version 2.0 (the "License");
  5.  *    you may not use this file except in compliance with the License.
  6.  *    You may obtain a copy of the License at
  7.  *
  8.  *       http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  *    Unless required by applicable law or agreed to in writing, software
  11.  *    distributed under the License is distributed on an "AS IS" BASIS,
  12.  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  *    See the License for the specific language governing permissions and
  14.  *    limitations under the License.
  15.  */
  16. package org.apache.ibatis.parsing;

  17. import java.util.ArrayList;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.Properties;
  21. import java.util.function.Supplier;

  22. import org.w3c.dom.CharacterData;
  23. import org.w3c.dom.Element;
  24. import org.w3c.dom.NamedNodeMap;
  25. import org.w3c.dom.Node;
  26. import org.w3c.dom.NodeList;

  27. /**
  28.  * @author Clinton Begin
  29.  */
  30. public class XNode {

  31.   private final Node node;
  32.   private final String name;
  33.   private final String body;
  34.   private final Properties attributes;
  35.   private final Properties variables;
  36.   private final XPathParser xpathParser;

  37.   public XNode(XPathParser xpathParser, Node node, Properties variables) {
  38.     this.xpathParser = xpathParser;
  39.     this.node = node;
  40.     this.name = node.getNodeName();
  41.     this.variables = variables;
  42.     this.attributes = parseAttributes(node);
  43.     this.body = parseBody(node);
  44.   }

  45.   public XNode newXNode(Node node) {
  46.     return new XNode(xpathParser, node, variables);
  47.   }

  48.   public XNode getParent() {
  49.     Node parent = node.getParentNode();
  50.     if (!(parent instanceof Element)) {
  51.       return null;
  52.     } else {
  53.       return new XNode(xpathParser, parent, variables);
  54.     }
  55.   }

  56.   public String getPath() {
  57.     StringBuilder builder = new StringBuilder();
  58.     Node current = node;
  59.     while (current instanceof Element) {
  60.       if (current != node) {
  61.         builder.insert(0, "/");
  62.       }
  63.       builder.insert(0, current.getNodeName());
  64.       current = current.getParentNode();
  65.     }
  66.     return builder.toString();
  67.   }

  68.   public String getValueBasedIdentifier() {
  69.     StringBuilder builder = new StringBuilder();
  70.     XNode current = this;
  71.     while (current != null) {
  72.       if (current != this) {
  73.         builder.insert(0, "_");
  74.       }
  75.       String value = current.getStringAttribute("id",
  76.           current.getStringAttribute("value",
  77.               current.getStringAttribute("property", (String) null)));
  78.       if (value != null) {
  79.         value = value.replace('.', '_');
  80.         builder.insert(0, "]");
  81.         builder.insert(0,
  82.             value);
  83.         builder.insert(0, "[");
  84.       }
  85.       builder.insert(0, current.getName());
  86.       current = current.getParent();
  87.     }
  88.     return builder.toString();
  89.   }

  90.   public String evalString(String expression) {
  91.     return xpathParser.evalString(node, expression);
  92.   }

  93.   public Boolean evalBoolean(String expression) {
  94.     return xpathParser.evalBoolean(node, expression);
  95.   }

  96.   public Double evalDouble(String expression) {
  97.     return xpathParser.evalDouble(node, expression);
  98.   }

  99.   public List<XNode> evalNodes(String expression) {
  100.     return xpathParser.evalNodes(node, expression);
  101.   }

  102.   public XNode evalNode(String expression) {
  103.     return xpathParser.evalNode(node, expression);
  104.   }

  105.   public Node getNode() {
  106.     return node;
  107.   }

  108.   public String getName() {
  109.     return name;
  110.   }

  111.   public String getStringBody() {
  112.     return getStringBody(null);
  113.   }

  114.   public String getStringBody(String def) {
  115.     return body == null ? def : body;
  116.   }

  117.   public Boolean getBooleanBody() {
  118.     return getBooleanBody(null);
  119.   }

  120.   public Boolean getBooleanBody(Boolean def) {
  121.     return body == null ? def : Boolean.valueOf(body);
  122.   }

  123.   public Integer getIntBody() {
  124.     return getIntBody(null);
  125.   }

  126.   public Integer getIntBody(Integer def) {
  127.     return body == null ? def : Integer.valueOf(body);
  128.   }

  129.   public Long getLongBody() {
  130.     return getLongBody(null);
  131.   }

  132.   public Long getLongBody(Long def) {
  133.     return body == null ? def : Long.valueOf(body);
  134.   }

  135.   public Double getDoubleBody() {
  136.     return getDoubleBody(null);
  137.   }

  138.   public Double getDoubleBody(Double def) {
  139.     return body == null ? def : Double.valueOf(body);
  140.   }

  141.   public Float getFloatBody() {
  142.     return getFloatBody(null);
  143.   }

  144.   public Float getFloatBody(Float def) {
  145.     return body == null ? def : Float.valueOf(body);
  146.   }

  147.   public <T extends Enum<T>> T getEnumAttribute(Class<T> enumType, String name) {
  148.     return getEnumAttribute(enumType, name, null);
  149.   }

  150.   public <T extends Enum<T>> T getEnumAttribute(Class<T> enumType, String name, T def) {
  151.     String value = getStringAttribute(name);
  152.     return value == null ? def : Enum.valueOf(enumType,value);
  153.   }

  154.   /**
  155.    * Return a attribute value as String.
  156.    *
  157.    * <p>
  158.    * If attribute value is absent, return value that provided from supplier of default value.
  159.    *
  160.    * @param name
  161.    *          attribute name
  162.    * @param defSupplier
  163.    *          a supplier of default value
  164.    * @return the string attribute
  165.    * @since 3.5.4
  166.    */
  167.   public String getStringAttribute(String name, Supplier<String> defSupplier) {
  168.     String value = attributes.getProperty(name);
  169.     return value == null ? defSupplier.get() : value;
  170.   }

  171.   public String getStringAttribute(String name) {
  172.     return getStringAttribute(name, (String) null);
  173.   }

  174.   public String getStringAttribute(String name, String def) {
  175.     String value = attributes.getProperty(name);
  176.     return value == null ? def : value;
  177.   }

  178.   public Boolean getBooleanAttribute(String name) {
  179.     return getBooleanAttribute(name, null);
  180.   }

  181.   public Boolean getBooleanAttribute(String name, Boolean def) {
  182.     String value = attributes.getProperty(name);
  183.     return value == null ? def : Boolean.valueOf(value);
  184.   }

  185.   public Integer getIntAttribute(String name) {
  186.     return getIntAttribute(name, null);
  187.   }

  188.   public Integer getIntAttribute(String name, Integer def) {
  189.     String value = attributes.getProperty(name);
  190.     return value == null ? def : Integer.valueOf(value);
  191.   }

  192.   public Long getLongAttribute(String name) {
  193.     return getLongAttribute(name, null);
  194.   }

  195.   public Long getLongAttribute(String name, Long def) {
  196.     String value = attributes.getProperty(name);
  197.     return value == null ? def : Long.valueOf(value);
  198.   }

  199.   public Double getDoubleAttribute(String name) {
  200.     return getDoubleAttribute(name, null);
  201.   }

  202.   public Double getDoubleAttribute(String name, Double def) {
  203.     String value = attributes.getProperty(name);
  204.     return value == null ? def : Double.valueOf(value);
  205.   }

  206.   public Float getFloatAttribute(String name) {
  207.     return getFloatAttribute(name, null);
  208.   }

  209.   public Float getFloatAttribute(String name, Float def) {
  210.     String value = attributes.getProperty(name);
  211.     return value == null ? def : Float.valueOf(value);
  212.   }

  213.   public List<XNode> getChildren() {
  214.     List<XNode> children = new ArrayList<>();
  215.     NodeList nodeList = node.getChildNodes();
  216.     if (nodeList != null) {
  217.       for (int i = 0, n = nodeList.getLength(); i < n; i++) {
  218.         Node node = nodeList.item(i);
  219.         if (node.getNodeType() == Node.ELEMENT_NODE) {
  220.           children.add(new XNode(xpathParser, node, variables));
  221.         }
  222.       }
  223.     }
  224.     return children;
  225.   }

  226.   public Properties getChildrenAsProperties() {
  227.     Properties properties = new Properties();
  228.     for (XNode child : getChildren()) {
  229.       String name = child.getStringAttribute("name");
  230.       String value = child.getStringAttribute("value");
  231.       if (name != null && value != null) {
  232.         properties.setProperty(name, value);
  233.       }
  234.     }
  235.     return properties;
  236.   }

  237.   @Override
  238.   public String toString() {
  239.     StringBuilder builder = new StringBuilder();
  240.     toString(builder, 0);
  241.     return builder.toString();
  242.   }

  243.   private void toString(StringBuilder builder, int level) {
  244.     builder.append("<");
  245.     builder.append(name);
  246.     for (Map.Entry<Object, Object> entry : attributes.entrySet()) {
  247.       builder.append(" ");
  248.       builder.append(entry.getKey());
  249.       builder.append("=\"");
  250.       builder.append(entry.getValue());
  251.       builder.append("\"");
  252.     }
  253.     List<XNode> children = getChildren();
  254.     if (!children.isEmpty()) {
  255.       builder.append(">\n");
  256.       for (XNode child : children) {
  257.         indent(builder, level + 1);
  258.         child.toString(builder, level + 1);
  259.       }
  260.       indent(builder, level);
  261.       builder.append("</");
  262.       builder.append(name);
  263.       builder.append(">");
  264.     } else if (body != null) {
  265.       builder.append(">");
  266.       builder.append(body);
  267.       builder.append("</");
  268.       builder.append(name);
  269.       builder.append(">");
  270.     } else {
  271.       builder.append("/>");
  272.       indent(builder, level);
  273.     }
  274.     builder.append("\n");
  275.   }

  276.   private void indent(StringBuilder builder, int level) {
  277.     for (int i = 0; i < level; i++) {
  278.       builder.append("    ");
  279.     }
  280.   }

  281.   private Properties parseAttributes(Node n) {
  282.     Properties attributes = new Properties();
  283.     NamedNodeMap attributeNodes = n.getAttributes();
  284.     if (attributeNodes != null) {
  285.       for (int i = 0; i < attributeNodes.getLength(); i++) {
  286.         Node attribute = attributeNodes.item(i);
  287.         String value = PropertyParser.parse(attribute.getNodeValue(), variables);
  288.         attributes.put(attribute.getNodeName(), value);
  289.       }
  290.     }
  291.     return attributes;
  292.   }

  293.   private String parseBody(Node node) {
  294.     String data = getBodyData(node);
  295.     if (data == null) {
  296.       NodeList children = node.getChildNodes();
  297.       for (int i = 0; i < children.getLength(); i++) {
  298.         Node child = children.item(i);
  299.         data = getBodyData(child);
  300.         if (data != null) {
  301.           break;
  302.         }
  303.       }
  304.     }
  305.     return data;
  306.   }

  307.   private String getBodyData(Node child) {
  308.     if (child.getNodeType() == Node.CDATA_SECTION_NODE
  309.         || child.getNodeType() == Node.TEXT_NODE) {
  310.       String data = ((CharacterData) child).getData();
  311.       data = PropertyParser.parse(data, variables);
  312.       return data;
  313.     }
  314.     return null;
  315.   }

  316. }