提问人:sita 提问时间:4/6/2023 最后编辑:sita 更新时间:4/6/2023 访问量:93
如何从 XML 中获取整个标记作为字符串
How to get entire tag as String from an 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,有些带有命名空间,有些没有。但唯一共同点是这两个标签。就像上面的例子标题和书一样。
如果我得到第一个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,只有标题和书牌标签是通用的,而不是命名空间。以下内容可能会因不同的 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。我能够在没有 namepsace 的情况下做到这一点,但是当命名空间也添加它时,命名空间会随着不同的 xml 而不断变化。我不确定如何读取标签值。不想使用 JAXB,因为我使用的 XML 非常大,我最终会基于不同的 XML 创建多个 POJO。
答:
1赞
vanje
4/6/2023
#1
无需提取实际命名空间。如果从 XPath 表达式中获取标头元素,则命名空间仍然存在。您只需将节点序列化为字符串即可。
下面是一个完整的示例:
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>
评论
0赞
sita
4/6/2023
我不知道节点到字符串的序列化。这是一个更好的代码。谢谢!
评论