以递归方式从XML中删除空节点
我想从XML元素中删除空节点。 这个xml是从供应商生成的,我没有xml生成的控制权。 但由于XML几乎没有空节点,我需要递归删除这些空节点。
这个xml来自OMElement,我使用[XMLUtils] [1] Sample XML从这个对象中获取一个Element
something something something else
由于D21是一个空节点,我想删除D21,因为现在D2是一个空节点,我想删除D2,但由于D有D1,我不想删除D.
同样,我有可能得到
现在,因为C是空的,我想删除C然后B,然后最终删除节点A.我试图在Node中使用removeChild()方法执行此操作
但到目前为止,我无法递归删除它们。 有什么建议可以递归删除它们吗?
我递归地尝试获取节点和节点长度。 但节点长度没有帮助
if(childNode.getChildNodes().getLength() == 0 ){ childNode.getParentNode().removeChild(childNode); }
问候
Dheeraj Joshi
这样做,只需创建一个“深入”的递归函数,然后在“备份树”的路上删除空节点,这将具有删除D21和D2的效果。
public static void main(String[] args) throws Exception { DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); String input = "something something something else "; Document document = builder.parse(new InputSource(new StringReader( input))); removeNodes(document); Transformer transformer = TransformerFactory.newInstance() .newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); StreamResult result = new StreamResult(new StringWriter()); transformer.transform(new DOMSource(document), result); System.out.println(result.getWriter().toString()); } public static void removeNodes(Node node) { NodeList list = node.getChildNodes(); for (int i = 0; i < list.getLength(); i++) { removeNodes(list.item(i)); } boolean emptyElement = node.getNodeType() == Node.ELEMENT_NODE && node.getChildNodes().getLength() == 0; boolean emptyText = node.getNodeType() == Node.TEXT_NODE && node.getNodeValue().trim().isEmpty(); if (emptyElement || emptyText) { node.getParentNode().removeChild(node); } }
产量
something something something else
我没有足够的代表来评论@Adam的解决方案,但我遇到了一个问题,即在删除节点后,该节点的最后一个兄弟被移动到索引零,导致它不能完全删除空元素。 修复是使用一个列表来保存我们想要递归调用删除的所有节点。
此外,还有一个错误删除了具有属性的空元素。
解决这两个问题:
public static void removeEmptyNodes(Node node) { NodeList list = node.getChildNodes(); List nodesToRecursivelyCall = new LinkedList(); for (int i = 0; i < list.getLength(); i++) { nodesToRecursivelyCall.add(list.item(i)); } for(Node tempNode : nodesToRecursivelyCall) { removeEmptyNodes(tempNode); } boolean emptyElement = node.getNodeType() == Node.ELEMENT_NODE && node.getChildNodes().getLength() == 0; boolean emptyText = node.getNodeType() == Node.TEXT_NODE && node.getNodeValue().trim().isEmpty(); if (emptyElement || emptyText) { if(!node.hasAttributes()) { node.getParentNode().removeChild(node); } } }
在DOM的顶级元素上使用getTextContent()
。 如果方法返回空字符串或null,则可以删除此节点,因为此节点和所有子节点都为空。 如果方法getTextContent()
不返回空字符串,则在当前节点的每个子节点上调用getTextContent
,依此类推。
见文档 。
public class RemoveEmprtElement { public static void main(String[] args) { ReadFile readFile =new ReadFile(); String strXml=readFile.readFileFromPath(new File("sampleXml4.xml")); RemoveEmprtElement elementEmprtElement=new RemoveEmprtElement(); DocumentBuilder dBuilder = null; Document doc = null; try { dBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); doc = dBuilder.parse(new ByteArrayInputStream(strXml.getBytes())); elementEmprtElement.getEmptyNodes(doc); TransformerFactory tf = TransformerFactory.newInstance(); Transformer trans = tf.newTransformer(); StreamResult result = new StreamResult(new StringWriter()); trans.transform(new DOMSource(doc), result); System.out.println(result.getWriter().toString()); }catch(Exception e) { e.printStackTrace(); } } private void getEmptyNodes(Document doc){ try { XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); XPathExpression expr = xpath.compile("//*[not(*)]"); Object resultNS = expr.evaluate(doc, XPathConstants.NODESET); NodeList nodes = (NodeList) resultNS; for(int i =0 ; i < nodes.getLength() ; i++){ Node node = nodes.item(i); boolean emptyElement = node.getNodeType() == Node.ELEMENT_NODE && node.getChildNodes().getLength() == 0; boolean emptyText = node.getNodeType() == Node.TEXT_NODE && node.getNodeValue().trim().isEmpty(); if (emptyElement || emptyText) { xmlNodeRemove(doc,findPath(node)); getEmptyNodes(doc); } } }catch(Exception e) { e.printStackTrace(); } } private void xmlNodeRemove(Document doc,String xmlNodeLocation){ try { XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); XPathExpression expr = xpath.compile(xmlNodeLocation); Object resultNS = expr.evaluate(doc, XPathConstants.NODESET); NodeList nodes = (NodeList) resultNS; Node node =nodes.item(0); if(node!=null && node.getParentNode()!=null && node.getParentNode().hasChildNodes()){ node.getParentNode().removeChild(node); } }catch(Exception e) { e.printStackTrace(); } } private String findPath(Node n) { String path=""; if(n==null){ return path; }else if(n.getNodeName().equals("#document")){ return ""; } else{ path=n.getNodeName(); path=findPath(n.getParentNode())+"/"+path; } return path; } }
只需使用字符串:
Pattern emptyValueTag = Pattern.compile("\\s*<\\w+/>"); Pattern emptyTagMultiLine = Pattern.compile("\\s*<\\w+>\n*\\s*\\w+>"); xml = emptyValueTag.matcher(xml).replaceAll(""); while (xml.length() != (xml = emptyTagMultiLine.matcher(xml).replaceAll("")).length()) { } return xml;