Java – performs DOM node to string conversion, but there is a namespace problem

So we have an XML document with a custom namespace (XML is generated by software beyond our control. It is parsed by Dom parser with unknown namespace; something of standard java7se / Xerces, but it is also outside our effective control.) The input data is as follows:

<?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>

The documents we get are available, XPath can query and traverse, and so on

Convert this document to a text format for writing to a data receiver using the standard transformer method described in one hundred SOS, "how do I change an XML document to a Java string?" Question:

Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"no");
transformer.setOutputProperty(OutputKeys.INDENT,"yes");
StringWriter stringwriter = new StringWriter();
transformer.transform (new DOMSource(theXMLDocument),new StreamResult(stringwriter));
return stringwriter.toString();

It's perfect

But now I want to convert a single arbitrary node in the document to a string The domsource constructor accepts the same node pointer as it accepts document (in fact, document is just a subclass of node, so it is the same API I know) Therefore, it is very useful to pass a single node in "the XML document" in the above code snippet... Until we reach something

At this time, transform() throws an exception:

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)
    ......

That makes sense ("com. Sun. Org. Apache" is hard to read, but anyway.) This makes sense because the namespace of custom attributes is declared at the root node, but now the transformer starts from the child node and can see the Declaration "above it" in the tree So I think I understand the problem, or at least the symptoms, but I don't know how to solve it

>If this is a string - to - document transformation, we will use the documentbuilderfactory instance and can call Setnamespaceaware (false), but this is another direction. > transform. It makes sense that all available attributes of setoutputproperty () do not affect the NamespaceURI lookup. > There is no corresponding setinputproperty or similar function. > The input parser does not support namespaces, which is how "upstream" code creates its documents for us I don't know how to give a specific status flag to the transformation code, which is what I really want to do. > I believe it is possible (in some way) to add an xmlns: customattr = "http: / / blitherblither" attribute to the thing node, which is the same as the root maintag But at that time, the output is no longer the same XML as the read XML, even if it "means" the same thing, and the text string will eventually be compared in the future We don't know if we need the exception before it is thrown, then we can add it and try again... Ick In this regard, changing the node will change the original document, which should actually be a read-only operation

Any suggestions? Is there a way to tell transformers, "look, don't emphasize whether your clumsy little head is a separate output. It's legal XML. It won't be parsed by itself (but you don't know), but just generate text, let's worry about its background"?

Solution

In view of your reference error message "namespace with prefix 'customattr' has not been declared yet",

<?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>

With this assumption, this is my suggestion: so you want to extract the "thing" node from the "big" XML The standard way to do this is to use a little XSLT You are ready to XSL transform:

Transformer transformer = transformerFactory.newTransformer(new StreamSource(new File("isolate-the-thing-node.xslt")));
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"no");
transformer.setParameter("elementName",stringWithCurrentThing);    // parameterize transformation for each Thing
...

Edit: @ Ti, please pay attention to the parameterization instruction above (and XSLT below)

File 'isolate the thing node XSLT 'may be the following:

<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>

I hope you can surpass "things":

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>