View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.common.xml;
20  
21  import org.jdom2.Attribute;
22  import org.jdom2.Document;
23  import org.jdom2.Element;
24  import org.jdom2.Namespace;
25  import org.jdom2.Parent;
26  import org.mycore.common.MCRConstants;
27  
28  import java.util.List;
29  
30  /**
31   * Builds an absolute XPath expression for a given element or attribute within a JDOM XML structure.
32   *
33   * @author Frank L\u00FCtzenkirchen
34   */
35  public class MCRXPathBuilder {
36  
37      /**
38       * Builds an absolute XPath expression for a given element or attribute within a JDOM XML structure.
39       * For each element that is not the root element, the XPath will also contain a position predicate.
40       * For all namespaces commonly used in MyCoRe, their namespace prefixes will be used.
41       *
42       * @param object a JDOM element or attribute
43       * @return absolute XPath of that object. In case there is a root Document, it will begin with a "/".
44       */
45      public static String buildXPath(Object object) {
46          if (object instanceof Element) {
47              return buildXPath((Element) object);
48          } else if (object instanceof Attribute) {
49              return buildXPath((Attribute) object);
50          } else {
51              return "";
52          }
53      }
54  
55      /**
56       * Builds an absolute XPath expression for the given attribute within a JDOM XML structure.
57       * For each element that is not the root element, the XPath will also contain a position predicate.
58       * For all namespaces commonly used in MyCoRe, their namespace prefixes will be used.
59       *
60       * @param attribute a JDOM attribute
61       * @return absolute XPath of that attribute. In case there is a root Document, it will begin with a "/".
62       */
63      public static String buildXPath(Attribute attribute) {
64          String parentXPath = buildXPath(attribute.getParent());
65          if (!parentXPath.isEmpty()) {
66              parentXPath += "/";
67          }
68          return parentXPath + "@" + attribute.getQualifiedName();
69      }
70  
71      /**
72       * Builds an absolute XPath expression for the given element within a JDOM XML structure.
73       * For each element that is not the root element, the XPath will also contain a position predicate.
74       * For all namespaces commonly used in MyCoRe, their namespace prefixes will be used.
75       *
76       * @param element a JDOM element
77       * @return absolute XPath of that element. In case there is a root Document, it will begin with a "/".
78       */
79      public static String buildXPath(Element element) {
80          if (element == null) {
81              return "";
82          }
83  
84          String parentXPath = buildXPath(element.getParent());
85          if ((!parentXPath.isEmpty()) || (element.getParent() instanceof Document)) {
86              parentXPath += "/";
87          }
88          return parentXPath + buildChildPath(element);
89      }
90  
91      /**
92       * Builds a local XPath fragment as combined namespace prefix, local element name and position predicate
93       */
94      public static String buildChildPath(Element element) {
95          return getNamespacePrefix(element) + element.getName() + buildPositionPredicate(element);
96      }
97  
98      /**
99       * Returns the namespace prefix for this element, followed by a ":",
100      * or the empty string if no namespace prefix known.
101      */
102     public static String getNamespacePrefix(Element element) {
103         Namespace nsElement = element.getNamespace();
104         for (Namespace ns : MCRConstants.getStandardNamespaces()) {
105             if (ns.equals(nsElement)) {
106                 return ns.getPrefix() + ":";
107             }
108         }
109 
110         String prefix = nsElement.getPrefix();
111         if ((prefix != null) && !prefix.isEmpty()) {
112             return prefix + ":";
113         } else {
114             return "";
115         }
116     }
117 
118     private static String buildPositionPredicate(Element element) {
119         Parent parent = element.getParent();
120         if ((parent instanceof Document) || (parent == null)) {
121             return "";
122         }
123 
124         Element parentElement = (Element) parent;
125         List<Element> siblings = parentElement.getChildren(element.getName(), element.getNamespace());
126         int pos = siblings.indexOf(element) + 1;
127 
128         return "[" + pos + "]";
129     }
130 }