Проблема здесь в том, что я каждый раз получаю разные 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 и 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>
Примечание. Это пространство имен приведено только для примера. Теперь я получаю это пространство имен. Я мог бы получить xmls с разными пространствами имен, только заголовок и тег книги будут общими, а не пространство имен. Ниже могут измениться для разных xmls.
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, но когда пространство имен добавлено, пространство имен также продолжает меняться с разными xmls. Я не уверен, как читать значения тегов. Не хочу использовать JAXB, так как XML, который я использую, довольно большой, и в конечном итоге я создам несколько POJO на основе разных XML.
Вам не нужно извлекать фактическое пространство имен. Если вы получаете свой элемент заголовка из своего выражения 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>
Я понятия не имел о сериализации узла в строку. Это лучший код. Спасибо!