在Java DOM中将节点的内部XML作为String获取
我有一个XML org.w3c.dom.Node,如下所示:
foo bar
如何将
部分作为字符串?
foo bar
同样的问题。 为了解决这个问题,我编写了这个辅助函数:
public String innerXml(Node node) { DOMImplementationLS lsImpl = (DOMImplementationLS)node.getOwnerDocument().getImplementation().getFeature("LS", "3.0"); LSSerializer lsSerializer = lsImpl.createLSSerializer(); NodeList childNodes = node.getChildNodes(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < childNodes.getLength(); i++) { sb.append(lsSerializer.writeToString(childNodes.item(i))); } return sb.toString(); }
对于org.w3c.dom.Node
,没有简单的方法。 getTextContent()
给出连接在一起的每个子节点的文本。 getNodeValue()
将为您提供当前节点的文本(如果它是Attribute
, CDATA
或Text
节点)。 因此,您需要使用getChildNodes()
, getNodeName()
和getNodeValue()
的组合来序列化节点以构建字符串。
您也可以使用存在的各种XML序列化库之一来完成此操作。 有XStream
甚至是JAXB。 这在这里讨论: Java中的XML序列化?
如果你正在使用jOOX ,你可以用类似jquery的语法包装你的节点,并在其上调用toString()
:
$(node).toString();
它在内部使用身份变换器,如下所示:
ByteArrayOutputStream out = new ByteArrayOutputStream(); Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); Source source = new DOMSource(element); Result target = new StreamResult(out); transformer.transform(source, target); return out.toString();
根据Andrey M的回答,我不得不稍微修改代码以获得完整的DOM文档。 如果你只是使用
NodeList childNodes = node.getChildNodes();
它没有包括我的根元素。 要包含root元素(并获取完整的.xml文档),我使用了:
public String innerXml(Node node) { DOMImplementationLS lsImpl = (DOMImplementationLS)node.getOwnerDocument().getImplementation().getFeature("LS", "3.0"); LSSerializer lsSerializer = lsImpl.createLSSerializer(); lsSerializer.getDomConfig().setParameter("xml-declaration", false); StringBuilder sb = new StringBuilder(); sb.append(lsSerializer.writeToString(node)); return sb.toString(); }
如果您不想使用外部库,以下解决方案可能会派上用场。 如果您有一个节点
并且您想要提取父元素的子元素,请按以下步骤操作:
StringBuilder resultBuilder = new StringBuilder(); // Get all children of the given parent node NodeList children = parent.getChildNodes(); try { // Set up the output transformer TransformerFactory transfac = TransformerFactory.newInstance(); Transformer trans = transfac.newTransformer(); trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); trans.setOutputProperty(OutputKeys.INDENT, "yes"); StringWriter stringWriter = new StringWriter(); StreamResult streamResult = new StreamResult(stringWriter); for (int index = 0; index < children.getLength(); index++) { Node child = children.item(index); // Print the DOM node DOMSource source = new DOMSource(child); trans.transform(source, streamResult); // Append child to end result resultBuilder.append(stringWriter.toString()); } } catch (TransformerException e) { //Error handling goes here } return resultBuilder.toString();
我遇到了问题,最后一个答案是’nodeToStream()’方法是未定义的; 因此,我的版本在这里:
public static String toString(Node node){ String xmlString = ""; try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); //transformer.setOutputProperty(OutputKeys.INDENT, "yes"); Source source = new DOMSource(node); StringWriter sw = new StringWriter(); StreamResult result = new StreamResult(sw); transformer.transform(source, result); xmlString = sw.toString (); } catch (Exception ex) { ex.printStackTrace (); } return xmlString; }
到目前为止,安德烈M的最佳解决方案需要一个特定的实现,这可能会在未来引发问题。 这是相同的方法,但只有JDK允许您进行序列化(即,配置为使用的内容)。
public static String innerXml(Node node) throws Exception { StringWriter writer = new StringWriter(); Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); NodeList childNodes = node.getFirstChild().getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { transformer.transform(new DOMSource(childNodes.item(i)), new StreamResult(writer)); } return writer.toString(); }
如果您正在处理文档而不是节点,则必须深入一级并使用node.getFirstChild().getChildNodes();
但是,为了使其更加健壮,您应该找到第一个元素,而不仅仅是理所当然地认为只有一个节点。 XML必须具有单个根元素,但可以包含多个节点,包括注释,实体和空白文本。
Node rootElement = docRootNode.getFirstChild(); while (rootElement != null && rootElement.getNodeType() != Node.ELEMENT_NODE) rootElement = rootElement.getNextSibling(); if (rootElement == null) throw new RuntimeException("No root element found in given document node."); NodeList childNodes = rootElement.getChildNodes();
如果我应该推荐一个库来处理它,请尝试JSoup,它主要用于HTML,但也适用于XML 。 我没有测试过。
Document doc = Jsoup.parse(xml, "", Parser.xmlParser()); fileContents.put(Attributes.BODY, document.body().html()); // versus: document.body().outerHtml()
我想延伸来自Andrey M的非常好的答案:
可能会发生节点不可序列化,这会导致某些实现出现以下exception:
org.w3c.dom.ls.LSException: unable-to-serialize-node: unable-to-serialize-node: The node could not be serialized.
我在Wildfly 13上运行的实现“ org.apache.xml.serialize.DOMSerializerImpl.writeToString(DOMSerializerImpl) ”遇到了这个问题。
为了解决这个问题,我建议稍微更改Andrey M.的代码示例:
private static String innerXml(Node node) { DOMImplementationLS lsImpl = (DOMImplementationLS) node.getOwnerDocument().getImplementation().getFeature("LS", "3.0"); LSSerializer lsSerializer = lsImpl.createLSSerializer(); lsSerializer.getDomConfig().setParameter("xml-declaration", false); NodeList childNodes = node.getChildNodes(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < childNodes.getLength(); i++) { Node innerNode = childNodes.item(i); if (innerNode!=null) { if (innerNode.hasChildNodes()) { sb.append(lsSerializer.writeToString(innerNode)); } else { sb.append(innerNode.getNodeValue()); } } } return sb.toString(); }
我还添加了Nyerguds的评论。 这适用于我在wildfly 13。
这是一个提取org.w3c.dom.Node内容的替代解决方案。 如果节点内容不包含xml标记,则此解决方案也适用:
private static String innerXml(Node node) throws TransformerFactoryConfigurationError, TransformerException { StringWriter writer = new StringWriter(); String xml = null; Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); transformer.transform(new DOMSource(node), new StreamResult(writer)); // now remove the outer tag.... xml = writer.toString(); xml = xml.substring(xml.indexOf(">") + 1, xml.lastIndexOf("")); return xml; }
在Lukas Eder的解决方案之上,我们可以像.NET一样提取innerXml,如下所示
public static String innerXml(Node node,String tag){ String xmlstring = toString(node); xmlstring = xmlstring.replaceFirst("<[/]?"+tag+">",""); return xmlstring; } public static String toString(Node node){ String xmlString = ""; Transformer transformer; try { transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); //transformer.setOutputProperty(OutputKeys.INDENT, "yes"); StreamResult result = new StreamResult(new StringWriter()); xmlString = nodeToStream(node, transformer, result); } catch (TransformerConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (TransformerFactoryConfigurationError e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (TransformerException e) { // TODO Auto-generated catch block e.printStackTrace(); }catch (Exception ex){ ex.printStackTrace(); } return xmlString; }
例如:
If Node name points to xml with string representation "ChristianBale " String innerXml = innerXml(name,"Name"); //returns "ChristianBale"