如何从XML中获得整个标记作为字符串



这里的问题是,我得到不同的xml与不同的命名空间每次。

我必须读取一个标签作为字符串,并将其传递给另一个服务。

让我们假设我得到这个xml一次

<?xml version="1.0" encoding="utf-8" ?>
<inventory>
<header>
<id>123</id>
</header>
<book>
<title>Snow Crash</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<isbn>0553380958</isbn>
<price>14.95</price>
</book>
</inventory>

我也得到这样的xml。命名空间是不同的。这只是个例子。

<?xml version="1.0" encoding="utf-8" ?>
<Category xmlns:in="uri.category.xsd.in.01">
<in:type>books</in:type>
<h:header xmlns:h="uri.header.xsd.01">
<h:id>123</h:id>
<h:memId>123</h:memId>
</h:header>
<b:book xmlns:b="uri.books.xsd.01">
<b:title>Snow Crash</b:title>
<b:author>Neal Stephenson</b:author>
<b:publisher>Spectra</b:publisher>
<b:isbn>0553380958</b:isbn>
<b:price>14.95</b:price>
</b:book>
</Category>

注意:每次我将得到不同的xml的一些有名称空间,一些没有。但唯一的共同点是这两个标签。就像上面的例子header and book.

如果我得到第一个xml我将像这样发送到另一个服务

<header>
<id>123</id>
</header>

如果我得到第二个xml作为输入,那么我应该把它发送到另一个服务

<h:header xmlns:h="uri.header.xsd.01">
<h:id>123</h:id>
<h:memId>123</h:memId>
</h:header>

注意:此命名空间仅作为示例。现在我得到了这个名称空间。我可能会得到具有不同名称空间的xml,只有标题和book标记是通用的,而不是名称空间。对于不同的xml,下面可能会有变化。

xmlns:h="uri.header.xsd.01"

我已经用DOM解析器和xpath解决了这个问题。

我写了一个方法来获取命名空间,就像上面的情况一样,它是"h:"在字符串上做一些操作,像下面这样。我想知道是否有更好的方法来做这件事。

public static String getNamespace(String s, Document doc) throws Exception{
String ns="";
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList) xpath.evaluate(s,doc, XPathConstants.NODESET);
Element element = (Element) nodeList.item(0);
String elementwithNS = element.toString().substring(1,element.toString().length()-1);
String namespace[]=elementwithNS.split(":");
if(namespace.length==3)
ns= namespace[0]+":";
return ns;
}
ns_Header = getNamespace("//*[local-name()='header']");//I get the namespace as h:if it is empty then empty string 
String header_close_tag = "</"+ns_Header+"header>"
String header = StringUtils.substringBetween(xml,"header",header_close_tag);
String header_tag = "<"+ns_Header+"header"+header+header_close_tag;

我还想读取头标签值,如id和memId。我可以在没有命名空间的情况下做到这一点,但是当添加命名空间时,名称空间也会随着不同的xml而不断变化。我不确定如何读取标签值。我不想使用JAXB,因为我使用的XML非常大,我最终会基于不同的XML创建多个POJO。

您不需要提取实际的名称空间。如果从XPath表达式获得header元素,名称空间仍然存在。您只需要将节点序列化为字符串。

下面是一个完整的例子:

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;
import java.io.StringReader;
import java.io.StringWriter;
public class XmlExample {
private static final String xmlWithoutNs = "<inventory>n" +
"<header>n" +
"    <id>123</id>n" +
"</header>n" +
" <book>n" +
"    <title>Snow Crash</title>n" +
"    <author>Neal Stephenson</author>n" +
"    <publisher>Spectra</publisher>n" +
"    <isbn>0553380958</isbn>n" +
"    <price>14.95</price>n" +
" </book>n" +
"</inventory>";
private static final String xmlWithNs = "<Category xmlns:in="uri.category.xsd.in.01">n" +
"<in:type>books</in:type>n" +
"<h:header xmlns:h="uri.header.xsd.01">n" +
"    <h:id>123</h:id>n" +
"    <h:memId>123</h:memId>n" +
"</h:header>n" +
" <b:book xmlns:b="uri.books.xsd.01">n" +
"    <b:title>Snow Crash</b:title>n" +
"    <b:author>Neal Stephenson</b:author>n" +
"    <b:publisher>Spectra</b:publisher>n" +
"    <b:isbn>0553380958</b:isbn>n" +
"    <b:price>14.95</b:price>n" +
" </b:book>n" +
"</Category>";
private static String xmlToString(Node node) throws TransformerException {
TransformerFactory fac = TransformerFactory.newInstance();
Transformer transformer;
transformer = fac.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(node), new StreamResult(writer));
return writer.toString();
}
private static String getHeaderAsString(Document doc) throws XPathExpressionException, TransformerException {
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile("/*/*[local-name() = 'header']");
Node node = (Node) expr.evaluate(doc, XPathConstants.NODE);
return xmlToString(node);
}
public static void main(String[] args) throws Exception {
DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance();
fac.setNamespaceAware(true);
DocumentBuilder builder = fac.newDocumentBuilder();
Document docWithNs = builder.parse(new InputSource(new StringReader(xmlWithNs)));
System.out.println("Example with Namespace:");
System.out.println(getHeaderAsString(docWithNs));
Document docWithoutNs = builder.parse(new InputSource(new StringReader(xmlWithoutNs)));
System.out.println("nExample without Namespace:");
System.out.println(getHeaderAsString(docWithoutNs));
}
}

输出:

Example with Namespace:
<h:header xmlns:h="uri.header.xsd.01">
<h:id>123</h:id>
<h:memId>123</h:memId>
</h:header>
Example without Namespace:
<header>
<id>123</id>
</header>

最新更新