Как удалить пространства имен из xml, используя java dom?
у меня есть следующий код
DocumentBuilderFactory dbFactory_ = DocumentBuilderFactory.newInstance();
Document doc_;
DocumentBuilder dBuilder = dbFactory_.newDocumentBuilder();
StringReader reader = new StringReader(s);
InputSource inputSource = new InputSource(reader);
doc_ = dBuilder.parse(inputSource);
doc_.getDocumentElement().normalize();
тогда я могу сделать
doc_.getDocumentElement();
и получить мой первый элемент, но проблема вместо того, чтобы быть job
элемент tns:job
.
Я знаю и пробовал использовать:
dbFactory_.setNamespaceAware(true);
но это не то, что я ищу, мне нужно что-то, чтобы полностью избавиться от пространств имен.
любая помощь будет оценили, Спасибо,
Джош
8 ответов
для узлов элементов и атрибутов:
Node node = ...;
String name = node.getLocalName();
даст вам локальную часть имени узла.
посмотреть узел.getLocalName()
используйте функцию Regex. Это решит эту проблему:
public static String removeXmlStringNamespaceAndPreamble(String xmlString) {
return xmlString.replaceAll("(<\?[^<]*\?>)?", ""). /* remove preamble */
replaceAll("xmlns.*?(\"|\').*?(\"|\')", "") /* remove xmlns declaration */
.replaceAll("(<)(\w+:)(.*?>)", "") /* remove opening tag prefix */
.replaceAll("(</)(\w+:)(.*?>)", ""); /* remove closing tags prefix */
}
, а не
dbFactory_.setNamespaceAware(true);
использовать
dbFactory_.setNamespaceAware(false);
хотя я согласен с Tomalak: в общем, пространства имен являются более полезными, чем вредными. Почему ты не хочешь их использовать?
Edit: этот ответ не отвечает на вопрос OP, который заключался в том, как избавиться от пространства имен приставки. Rd01 предоставил правильный ответ на этот вопрос.
вы can предварительно обработайте XML, чтобы удалить все пространства имен, если это абсолютно необходимо. Я бы рекомендовал против этого, поскольку удаление пространств имен из XML-документа по сути сопоставимо с удалением пространств имен из структуры программирования или библиотеки - вы рискуете столкнуться с именами и потерять способность различать когда-то различные элементы. Тем не менее, это твои похороны. ;-)
это преобразование XSLT удаляет все пространства имен из любого XML документ.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="node()|@*" />
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{local-name()}">
<xsl:apply-templates select="node()|@*" />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
примените его к XML-документу. Примеров Java для этого должно быть много, даже на этом сайте. Полученный документ будет иметь точно такую же структуру и макет, только без пространств имен.
public static void wipeRootNamespaces(Document xml) {
Node root = xml.getDocumentElement();
NodeList rootchildren = root.getChildNodes();
Element newroot = xml.createElement(root.getNodeName());
for (int i=0;i<rootchildren.getLength();i++) {
newroot.appendChild(rootchildren.item(i).cloneNode(true));
}
xml.replaceChild(newroot, root);
}
Tomalak, одно исправление вашего XSLT (в 3-м шаблоне):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="node() | @*" />
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<!-- Here! -->
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
размер входного XML также необходимо учитывать при выборе решения. Для больших xmls размером ~100k, возможно, если ваш ввод из веб-службы, вам также необходимо учитывать последствия сборки мусора при манипулировании большой строкой. Мы использовали строку.replaceAll раньше, и это вызвало частые ООМ в производстве с размером кучи 1,5 г из-за способа replaceAll реализуется.
можно ссылку http://app-inf.blogspot.com/2013/04/pitfalls-of-handling-large-string.html для наших выводов.
Я не уверен, как XSLT имеет дело с большими строковыми объектами, но мы закончили разбор строки вручную, чтобы удалить префиксы в одном разборе, чтобы избежать создания дополнительных больших объектов java.
public static String removePrefixes(String input1) {
String ret = null;
int strStart = 0;
boolean finished = false;
if (input1 != null) {
//BE CAREFUL : allocate enough size for StringBuffer to avoid expansion
StringBuffer sb = new StringBuffer(input1.length());
while (!finished) {
int start = input1.indexOf('<', strStart);
int end = input1.indexOf('>', strStart);
if (start != -1 && end != -1) {
// Appending anything before '<', including '<'
sb.append(input1, strStart, start + 1);
String tag = input1.substring(start + 1, end);
if (tag.charAt(0) == '/') {
// Appending '/' if it is "</"
sb.append('/');
tag = tag.substring(1);
}
int colon = tag.indexOf(':');
int space = tag.indexOf(' ');
if (colon != -1 && (space == -1 || colon < space)) {
tag = tag.substring(colon + 1);
}
// Appending tag with prefix removed, and ">"
sb.append(tag).append('>');
strStart = end + 1;
} else {
finished = true;
}
}
//BE CAREFUL : use new String(sb) instead of sb.toString for large Strings
ret = new String(sb);
}
return ret;
}
вместо использования TransformerFactory, а затем вызова transform на нем (который вводил пустое пространство имен, я преобразовал следующим образом:
OutputStream outputStream = new FileOutputStream(new File(xMLFilePath));
OutputFormat outputFormat = new OutputFormat(doc, "UTF-8", true);
outputFormat.setOmitComments(true);
outputFormat.setLineWidth(0);
XMLSerializer serializer = new XMLSerializer(outputStream, outputFormat);
serializer.serialize(doc);
outputStream.close();