如何更改DOM中每个节点上的命名空间?

在给定w3c DOM(Java的默认实现,特别是)中,我如何更改该DOM中每个元素/属性/节点的名称空间? 有效地,优选地。 DOM上似乎没有setNamespaceURI方法,这很不方便。

我已经尝试过XSL方法,但是它们无法在JAXP变换器中工作(尽管它们在Saxon9B中可以正常工作,但由于其他各种原因我无法使用它)。

基本上,我需要一个纯粹的核心java解决方案,它允许我获取一个文档并更改其命名空间。

根据我非常偏见的意见,你想要的将是一个巨大的痛苦的屁股。 我可以看到类型转换地狱和许多递归for循环所需要的可靠性! 啊,Java的默认实现,我讨厌你的NPE:内部,逆向逻辑,简单操作所需的额外步骤!

所以,是的,我的建议将是针对每个可能的节点类型进行类型转换的循环的递归,基于我个人的经验,Java的默认实现很糟糕。

这在名称空间感知DOM上效率不高。 您必须在要更改其名称空间的每个后代元素上使用DOM Level 3 Core方法Document.renameNode ( javadoc )。 (通常不需要更改这么多的Attr节点,因为没有前缀的Attr节点的名称空间始终为null,而不是Element的名称空间。)

如果您只想将一个名称空间替换为另一个名称空间,那么使用名称空间不知道的DOM可能会更快,只需更改有问题的xmlns属性即可。 你应该能够通过将DOMConfiguration’namespaces ‘参数设置为false来获得一个名称空间不知道的DOM,但是我没有在Java中尝试这个,而且这是一个模糊的小东西,DOM imps会出错。

如果intent只是更改名称空间,那么只需使用一些流编辑器将NS映射更改为URL。

Namspace或多或少是命名空间前缀和URI之间的绑定。 为了快速更改名称空间,只需更改映射:

之前:xmlns:myNS =“my-namespace-uri”

之后:xmlns:myNS =“my-new-namespace-uri”

如果intent只是改变命名空间,那么基本上改变映射就足够了。 此外,如果XML Document具有默认命名空间,则更改默认命名空间URL值将更改整个文档的命名空间。

之前:xmlns =“my-namespace-uri”

之后:xmlns =“my-new-namespace-uri”

在给定w3c DOM(Java的默认实现,特别是)中,我如何更改该DOM中每个元素/属性/节点的名称空间? 有效地,优选地。

我不认为有一个有效的解决方案也很强大。 你不能只重命名根元素上的东西。 考虑这些文件:

文档1

        

文档2

         

文档3

         

这三个文档在名称空间感知DOM中是等效的。 您可以针对其中任何一个运行相同的命名空间XPath查询 。

由于DOM允许您准确指定节点应该如何命名空间,因此不存在更改命名空间的全部一步调用。 您需要遍历DOM,不仅要考虑前缀和URI值,还要考虑它们在任何给定时间的范围 。

这个XSLT可以与Transformer一起使用,将命名空间命名为urn:fleet命名为urn:new

                  

注意事项:处理命名空间属性需要进一步调整; 摇摇欲坠的urn:fleet声明可以留下来,这是凌乱的,但在很大程度上是无关紧要的; 可能是其他我没想过的东西。

通过将targetnamespace属性应用于根元素,在没有定义的名称空间前缀的每个元素上更改名称空间。 执行此操作还需要您使用命名空间前缀更改每个元素。 您可以手动更改此前缀,也可以编写一些脚本逻辑来遍历DOM树,以便仅在必要时应用它。

以下是有关targetnamespace属性和nonamespaceschema属性的更多内容:

http://www.xml.com/pub/a/2000/11/29/schemas/part1.html?page=8 http://www.computerpoweruser.com/editorial/article.asp?article=articles%2Farchive %2Fc0407%2F48c07%2F48c07.asp

您可以将DOM树复制到另一棵树,并在处理过程中进行一些调整。 例如,使用org.apache.xml.utils.DOMBuilder作为ContentHandler的实现,您可以以这种方式覆盖方法:

 public void startElement(String ns, String localName, String name, Attributes atts) throws SAXException { super.startElement("new_namespace", localName, name, atts); } 

DOMBuilder将在复制期间处理所有脏工作,只留下命名空间替换逻辑。

如果您可以使用Xerces类,则可以创建一个DOMParser,用您修复的URI替换属性和元素的URI:

 import org.apache.xerces.parsers.DOMParser; public static class MyDOMParser extends DOMParser { private Map fixupMap = ...; @Override protected Attr createAttrNode(QName attrQName) { if (fixupMap.containsKey(attrQName.uri)) attrQName.uri = fixupMap.get(attrQName.uri); return super.createAttrNode(attrQName); } @Override protected Element createElementNode(QName qName) { if (fixupMap.containsKey(qName.uri)) qName.uri = fixupMap.get(qName.uri); return super.createElementNode(qName); } } 

在其他地方,您可以解析为DOM文档:

 DOMParse p = new MyDOMParser(...); p.parse(new InputSource(inputStream)); Document doc = p.getDocument(); 

给定DOM Document的此代码将返回一个新的DOM Document,其中应用了一组给定的名称空间URI转换(uriMap)。 键必须是源文档中的URI,目标文档中的替换URI的值。 未知的名称空间URI通过不变。 它知道更改xmlns:*属性的值,但不会更改可能碰巧将名称空间URI作为其值的其他属性(例如XSD targetNamespace)

 private static Node makeClone(Node kid, Node to, Map uriMap) { Document doc = to.getNodeType() == Node.DOCUMENT_NODE ? (Document) to : to.getOwnerDocument(); if (kid.getNodeType() == Node.ELEMENT_NODE) { String newURI = uriMap.containsKey(kid.getNamespaceURI()) ? uriMap.get(kid.getNamespaceURI()) : kid.getNamespaceURI(); Element clone = doc.createElementNS(newURI, kid.getNodeName()); to.appendChild(clone); for (int i = 0; i < kid.getAttributes().getLength(); i++) { Attr attr = (Attr) kid.getAttributes().item(i); String newAttrURI = uriMap.containsKey(attr.getNamespaceURI()) ? uriMap.get(attr.getNamespaceURI()) : attr.getNamespaceURI(); String newValue = attr.getValue(); if (attr.getNamespaceURI() != null && attr.getNamespaceURI().equals( "http://www.w3.org/2000/xmlns/") && uriMap.containsKey(attr.getValue())) newValue = uriMap.get(attr.getValue()); clone.setAttributeNS(newAttrURI, attr.getNodeName(), newValue); } return clone; } Node clone = kid.cloneNode(false); doc.adoptNode(clone); to.appendChild(clone); return clone; } private static void copyKidsChangingNS(Node from, Node to, Map uriMap) { NodeList kids = from.getChildNodes(); for (int i = 0; i < kids.getLength(); i++) { Node kid = kids.item(i); Node clone = makeClone(kid, to, uriMap); copyKidsChangingNS(kid, clone, uriMap); } } public static Document changeDocNS(Document doc, Map uriMap) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); DocumentBuilder db = dbf.newDocumentBuilder(); Document newDoc = db.newDocument(); copyKidsChangingNS(doc, newDoc, uriMap); return newDoc; }