Ответ 1
Для узлов Element и Attribute:
Node node = ...;
String name = node.getLocalName();
предоставит вам локальную часть имени node.
У меня есть следующий код
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);
но это просто не то, что я ищу, мне нужно что-то, чтобы полностью избавиться от пространств имен.
Любая помощь будет оценена, Спасибо,
Джош
Для узлов Element и Attribute:
Node node = ...;
String name = node.getLocalName();
предоставит вам локальную часть имени node.
Используйте функцию Regex. Это решит проблему:
public static String removeXmlStringNamespaceAndPreamble(String xmlString) {
return xmlString.replaceAll("(<\\?[^<]*\\?>)?", ""). /* remove preamble */
replaceAll("xmlns.*?(\"|\').*?(\"|\')", "") /* remove xmlns declaration */
.replaceAll("(<)(\\w+:)(.*?>)", "$1$3") /* remove opening tag prefix */
.replaceAll("(</)(\\w+:)(.*?>)", "$1$3"); /* remove closing tags prefix */
}
Вместо
dbFactory_.setNamespaceAware(true);
Использование
dbFactory_.setNamespaceAware(false);
Хотя я согласен с Томалаком: в общем, пространства имен более полезны, чем вредные. Почему вы не хотите их использовать?
Изменить: этот ответ не отвечает на вопрос OP, а именно, как избавиться от префиксов пространства имен. RD01 дал правильный ответ на этот вопрос.
Вы можете предварительно обработать 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 (в третьем шаблоне):
<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, возможно, если ваш вход от веб-службы, вам также нужно учитывать последствия сбора мусора при манипулировании большой строкой. Раньше мы использовали String.replaceAll, и это вызывало частые OOM в производстве с размером кучи 1.5G из-за того, как был реализован метод replaceAll.
Вы можете ссылаться на http://app-inf.blogspot.com/2013/04/pitfalls-of-handling-large-string.html для наших результатов.
Я не уверен, как XSLT имеет дело с большими объектами String, но мы закончили синтаксический анализ строки вручную, чтобы удалить префиксы в одном разборе, чтобы избежать создания дополнительных больших объектов 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 и последующего вызова на него (который вводил пустое пространство имен, я преобразовал следующее:
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();