001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2015 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see http://www.gnu.org/licenses. 027 */ 028 029package edu.wisc.ssec.mcidasv.util; 030 031import java.util.ArrayList; 032import java.util.List; 033 034import org.w3c.dom.Attr; 035import org.w3c.dom.Element; 036import org.w3c.dom.NamedNodeMap; 037import org.w3c.dom.Node; 038import org.w3c.dom.NodeList; 039 040/** 041 * A collection of utilities for XML.. 042 * 043 */ 044public abstract class XmlUtil extends ucar.unidata.xml.XmlUtil { 045 046 /** 047 * Print all the attributes of the given node 048 * 049 * @param parent 050 */ 051 public static void printNode(Node parent) { 052 if (parent==null) { 053 System.out.println("null node!"); 054 return; 055 } 056 System.out.println(parent.getNodeName() + " node:"); 057 NamedNodeMap attrs = parent.getAttributes(); 058 for(int i = 0 ; i<attrs.getLength() ; i++) { 059 Attr attribute = (Attr)attrs.item(i); 060 System.out.println(" " + attribute.getName()+" = "+attribute.getValue()); 061 } 062 } 063 064 /** 065 * Find all of the descendant elements of the given parent Node 066 * whose tag name.equals the given tag. 067 * 068 * @param parent The root of the xml dom tree to search. 069 * @param tag The tag name to match. 070 * @return The list of descendants that match the given tag. 071 */ 072 public static List<String> findDescendantNamesWithSeparator(Node parent, String tag, String separator) { 073 List<String> found = new ArrayList<>(); 074 findDescendantNamesWithSeparator(parent, tag, "", separator, found); 075 return found; 076 } 077 078 /** 079 * Find all of the descendant elements of the given parent Node 080 * whose tag name equals the given tag. 081 * 082 * @param parent The root of the xml dom tree to search. 083 * @param tag The tag name to match. 084 * @param found The list of descendants that match the given tag. 085 */ 086 private static void findDescendantNamesWithSeparator(Node parent, String tag, String descendants, String separator, List<String> found) { 087 if (parent instanceof Element) { 088 String elementName = ((Element)parent).getAttribute("name"); 089 if (!elementName.isEmpty()) { 090 descendants += ((Element)parent).getAttribute("name"); 091 } 092 if (parent.getNodeName().equals(tag)) { 093 found.add(descendants); 094 } 095 if (!elementName.isEmpty()) { 096 descendants += separator; 097 } 098 } 099 NodeList children = parent.getChildNodes(); 100 for (int i = 0; i < children.getLength(); i++) { 101 Node child = children.item(i); 102 findDescendantNamesWithSeparator(child, tag, descendants, separator, found); 103 } 104 } 105 106 /** 107 * Find the element described by nameList (path). 108 * 109 * @param parent 110 * @param nameList 111 * 112 * @return {@code Element} described by the given path, or {@code null} if 113 * there was a problem. 114 */ 115 public static Element getElementAtNamedPath(Node parent, List<String> nameList) { 116 return getMakeElementAtNamedPath(parent, nameList, "", false); 117 } 118 119 /** 120 * Make the element described by nameList (path). 121 * 122 * @param parent 123 * @param nameList 124 * 125 * @return {@code Element} described by the given path, or {@code null} if 126 * there was a problem. 127 */ 128 public static Element makeElementAtNamedPath(Node parent, List<String> nameList, String tagname) { 129 return getMakeElementAtNamedPath(parent, nameList, tagname, true); 130 } 131 132 /** 133 * Find the element described by nameList (path). 134 * 135 * @param parent 136 * @param nameList 137 * 138 * @return {@code Element} described by the given path, or {@code null} if 139 * there was a problem. 140 */ 141 public static Element getMakeElementAtNamedPath(Node parent, List<String> nameList, String tagName, boolean makeNew) { 142 Element thisElement = null; 143 if ((parent instanceof Element) && !nameList.isEmpty()) { 144 for (int i=0; i < nameList.size(); i++) { 145 String thisName = nameList.get(i); 146 NodeList children = parent.getChildNodes(); 147 boolean foundChild = false; 148 for (int j = 0; j < children.getLength(); j++) { 149 Node child = children.item(j); 150 if (!(child instanceof Element)) { 151 continue; 152 } 153 if (XmlUtil.getAttribute(child, "name").equals(thisName)) { 154 if (i == (nameList.size() - 1)) { 155 thisElement = (Element)child; 156 } 157 parent = child; 158 foundChild = true; 159 break; 160 } 161 } 162 163 // Didn't find it where we expected to. Create a new one. 164 if (makeNew && !foundChild && (parent instanceof Element)) { 165 try { 166 Element newElement = XmlUtil.create(tagName, (Element)parent); 167 newElement.setAttribute("name", thisName); 168 parent.appendChild(newElement); 169 parent = newElement; 170 thisElement = newElement; 171 } catch (Exception ex) { 172 System.err.println("Error making new " + tagName + " node named " + thisName); 173 break; 174 } 175 } 176 } 177 } 178 return thisElement; 179 } 180 181 /** 182 * Added by TJJ Feb 2014 183 * 184 * This method ensures that the output String has only 185 * valid XML unicode characters as specified by the 186 * XML 1.0 standard. For reference, please see 187 * <a href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char">the 188 * standard</a>. This method will return an empty 189 * String if the input is null or empty. 190 * 191 * @param in The String whose non-valid characters we want to remove. 192 * @return The in String, stripped of non-valid characters. 193 */ 194 195 public static String stripNonValidXMLCharacters(String in) { 196 if ((in == null) || in.isEmpty()) { 197 return ""; // vacancy test. 198 } 199 StringBuilder out = new StringBuilder(in.length()); // Used to hold the output. 200 for (int i = 0; i < in.length(); i++) { 201 char current = in.charAt(i); // Used to reference the current character. 202 // NOTE: No IndexOutOfBoundsException caught here; it should not happen. 203 if ((current == 0x9) || 204 (current == 0xA) || 205 (current == 0xD) || 206 ((current >= 0x20) && (current <= 0xD7FF)) || 207 ((current >= 0xE000) && (current <= 0xFFFD)) || 208 ((current >= 0x10000) && (current <= 0x10FFFF))) 209 { 210 out.append(current); 211 } 212 } 213 return out.toString(); 214 } 215 216}