Java 正在进行DOM节点到字符串的转换,但存在名称空间问题

Java 正在进行DOM节点到字符串的转换,但存在名称空间问题,java,xml,Java,Xml,因此,我们有一个带有自定义名称空间的XML文档。(XML是由我们不控制的软件生成的。它由不知道名称空间的DOM解析器解析;标准的Java7SE/Xerces,但也不在我们的有效控制范围内。)输入数据如下所示: <?xml version="1.0" encoding="ISO-8859-1" standalone="no"?> <MainTag xmlns="http://BlahBlahBlah" xmlns:CustomAttr="http://BlitherBlither

因此,我们有一个带有自定义名称空间的XML文档。(XML是由我们不控制的软件生成的。它由不知道名称空间的DOM解析器解析;标准的Java7SE/Xerces,但也不在我们的有效控制范围内。)输入数据如下所示:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<MainTag xmlns="http://BlahBlahBlah" xmlns:CustomAttr="http://BlitherBlither">
    .... 18 blarzillion lines of XML ....
    <Thing CustomAttr:gibberish="borkborkbork" ... />
    .... another 27 blarzillion lines ....
</MainTag>
而且它工作得很好

但是现在我想把文档中的任意节点转换成字符串。
DOMSource
构造函数接受节点指针的方式与接受
文档的方式相同(事实上,文档只是节点的一个子类,所以据我所知,它是相同的API)。因此,在上面的代码片段中,在“XMLDocument”的位置传递单个节点非常有用。。。直到我们到达
的事情

此时,
transform()
抛出一个异常:

java.lang.RuntimeException: Namespace for prefix 'CustomAttr' has not been declared.
    at com.sun.org.apache.xml.internal.serializer.SerializerBase.getNamespaceURI(Unknown Source)
    at com.sun.org.apache.xml.internal.serializer.SerializerBase.addAttribute(Unknown Source)
    at com.sun.org.apache.xml.internal.serializer.ToUnknownStream.addAttribute(Unknown Source)
    ......
这是有道理的。(读“com.sun.org.apache”很奇怪,但不管怎样)这是有道理的,因为自定义属性的名称空间是在根节点声明的,但是现在转换器从子节点开始,在树中看不到“上面”的声明。所以我想我理解这个问题,或者至少是症状,但我不知道如何解决它

  • 如果这是一个字符串到文档的转换,我们将使用
    DocumentBuilderFactory
    实例,并可以调用
    .setNamespaceAware(false)
    ,但这将朝着另一个方向发展

  • transformer.setOutputProperty()
    的所有可用属性都不会影响namespaceURI查找,这是有意义的

  • 没有相应的
    setInputProperty
    或类似函数

  • 输入解析器不知道名称空间,“上游”代码就是这样创建文档交给我们的。我不知道如何将特定的状态标志传递给转换代码,我想这是我真正想做的

  • 我相信可以(以某种方式)添加
    xmlns:CustomAttr=”http://BlitherBlither“
    属性,与根MainTag的属性相同。但此时,输出不再是与读入内容相同的XML,即使它“表示”相同的内容,并且文本字符串最终将在将来进行比较。在抛出异常之前,我们不知道是否需要它,然后我们可以添加它并重试。。。哎呀。因此,更改节点将更改原始文档,这实际上应该是一个只读操作


建议?有没有什么方法可以告诉转换程序,“听着,别在输出是否是合法的XML上过分强调你那愚蠢的小脑袋,它不会自己被解析回来(但你不知道),只要生成文本,让我们担心它的上下文”

给出你引用的错误消息“尚未声明前缀“CustomAttr”的命名空间。”, 我假设您的伪代码大致如下:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<MainTag xmlns="http://BlahBlahBlah" xmlns:CustomAttr="http://BlitherBlither">
    .... 18 blarzillion lines of XML ....
    <Thing CustomAttr:attributeName="borkborkbork" ... />
    .... another 27 blarzillion lines ....
</MainTag>
编辑:@Ti,请注意上面(以及xslt下面)的参数化说明

文件“isolate The thing node.xslt”可能是以下内容的一种风格:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:custom0="http://BlahBlahBlah"
    xmlns:custom1="http://BlitherBlither"
    version="1.0">
    <xsl:param name="elementName">to-be-parameterized</xsl:param>
    <xsl:output encoding="utf-8" indent="yes" method="xml" omit-xml-declaration="no" />

    <xsl:template match="/*" priority="2" >
            <!--<xsl:apply-templates select="//custom0:Thing" />-->
            <!-- changed to parameterized selection: -->
            <xsl:apply-templates select="custom0:*[local-name()=$elementName]" />
    </xsl:template>

    <xsl:template match="node() | @*" priority="1">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*" />
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

参数化

希望这能帮助您克服“Thing”问题:)

我已成功解析提供的文档,获取Thing节点并将其打印出来

请看一下:

节点字符串

private static String nodeToString(Node node) {
  StringWriter sw = new StringWriter();
  try {
    Transformer t = TransformerFactory.newInstance().newTransformer();
    t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
    t.setOutputProperty(OutputKeys.INDENT, "yes");
    t.transform(new DOMSource(node), new StreamResult(sw));
  } catch (TransformerException te) {
    System.out.println("nodeToString Transformer Exception");
  }
  return sw.toString();
}
输出

Whole document: 

<?xml version="1.0" encoding="UTF-8"?><MainTag xmlns="http://BlahBlahBlah" xmlns:CustomAttr="http://BlitherBlither">
    <Thing CustomAttr="borkborkbork"/>
</MainTag>

Just Thing: 

<?xml version="1.0" encoding="UTF-8"?><Thing CustomAttr="borkborkbork"/>

您没有显示您输入的转换失败的XSL。您有没有理由不能从文档根目录下运行XSL,而不必将其传递给一个裸
节点?@JimGarrison我对XML的了解不够,无法理解您的问题,但我可以声明一个事实,我们没有涉及任何XSL;合作伙伴de就是我上面所展示的。我们只需要一个纯文本输出。这对我来说没有意义。CustomAttr名称空间前缀甚至没有在CustomAttr属性中使用。该属性碰巧有一个名称也用作名称空间前缀,但这并不相关。你能给我们展示一下其余的内容吗?@flup:Fixed,I相信我,从我从数据中提取出来的东西。(我对XML不太了解,因为习惯,抱歉)至于使用那样的XSLT转换,谢谢,我会研究一下。我们必须在不同的元素标记(上面的
东西
)上进行几十万次节点到文本的转换,所以我需要找到一些方法来生成新的select=“//somepathhere:Thing”并每次将其插入到输入流中。这并不难做到(ByteBrrayInputStream等),但速度会很慢。再次感谢您的提示!@TiStrga,关于“我们必须将此节点转换为文本十万次…”。。。,我编辑了答案,因此它包含了关于如何进行参数化转换的说明,这样您就可以将其他“东西”作为'elementName'参数传递到xslt中。我将此标记为答案,因为它似乎是最佳解决方案。我实际上没有得到任何运行;Java Transformer构造函数失败,出现“无法编译样式表”异常,出现了一个毫无用处的文本
错误:“语法错误在“”。
(没有行号或其他有用的指针,只是“游戏结束,走开”)。我们会继续努力的。谢谢你的出发点!您好@TiStrga,为了解决您的最新问题,我建议检查xslt的有效性。使用外部XML工具(例如XMLSpy)来实现这一点。另外,为了安全起见,添加XML声明()作为第一行,可能是因为您使用的Java类被阻塞了。
Node rootElement = d.getDocumentElement();
System.out.println("Whole document: \n");  
System.out.println(nodeToString(rootElement));
Node thing = rootElement.getChildNodes().item(1);
System.out.println("Just Thing: \n");  
System.out.println(nodeToString(thing));
private static String nodeToString(Node node) {
  StringWriter sw = new StringWriter();
  try {
    Transformer t = TransformerFactory.newInstance().newTransformer();
    t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
    t.setOutputProperty(OutputKeys.INDENT, "yes");
    t.transform(new DOMSource(node), new StreamResult(sw));
  } catch (TransformerException te) {
    System.out.println("nodeToString Transformer Exception");
  }
  return sw.toString();
}
Whole document: 

<?xml version="1.0" encoding="UTF-8"?><MainTag xmlns="http://BlahBlahBlah" xmlns:CustomAttr="http://BlitherBlither">
    <Thing CustomAttr="borkborkbork"/>
</MainTag>

Just Thing: 

<?xml version="1.0" encoding="UTF-8"?><Thing CustomAttr="borkborkbork"/>
<?xml version="1.0" encoding="UTF-8"?><Thing xmlns:CustomAttr="http://BlitherBlither" CustomAttr:attributeName="borkborkbork" xmlns="http://BlahBlahBlah"/>