9

これで、カスタム名前空間を持つ 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>

取得したドキュメントは使用可能で、xpath クエリ可能で、トラバース可能などです。

このドキュメントをテキスト形式に変換してデータ シンクに書き出すには、100 の SO「how do I change my XML Document into a Java string?」で説明されている標準の Transformer アプローチを使用します。質問:

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();

そしてそれは完全に機能します。

しかし今、そのドキュメントから個々の任意のノードを文字列に変換したいと思います。コンストラクターは、Node ポインターを受け入れるのDOMSourceと同じように Node ポインターを受け入れますDocument(実際、Document は Node の単なるサブクラスであるため、私が知る限り、同じ API です)。したがって、上記のスニペットの「theXMLDocument」の代わりに個々のノードを渡すとうまく機能します... Thing.

その時点で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」は読むのが奇妙ですが、何でもあります。カスタム属性の名前空間がルート ノードで宣言されているため、これは理にかなっていますが、トランスフォーマーは子ノードで開始され、次のことができます。ツリーの「上」にある宣言は表示されません。だから私は問題、または少なくとも症状を理解していると思いますが、それを解決する方法はわかりません。

  • これが String から Document への変換である場合、DocumentBuilderFactoryインスタンスを使用して を呼び出すことができます.setNamespaceAware(false)が、これは逆方向です。

  • で使用可能なプロパティはどれもtransformer.setOutputProperty()、namespaceURI ルックアップに影響を与えません。これは理にかなっています。

  • そのような対応setInputPropertyまたは類似の機能はありません。

  • 入力パーサーは名前空間を認識していませんでした。これが、「アップストリーム」コードがドキュメントを作成して私たちに渡す方法でした。その特定のステータスフラグを変換コードに渡す方法がわかりません。これは私が本当にやりたいことだと思います。

  • ルートMainTagxmlns:CustomAttr="http://BlitherBlither"が持っていたのと同じように、Thing ノードに属性を (どういうわけか) 追加できると思います。しかし、その時点で、たとえそれが同じことを「意味」していたとしても、出力は読み込まれたものと同一の XML ではなくなり、テキスト文字列は最終的に将来比較されることになります。例外がスローされるまで、それが必要かどうかはわかりません。その後、追加して再試行できます... ick. さらに言えば、ノードを変更すると元のドキュメントが変更されるため、これは実際には読み取り専用の操作である必要があります。

アドバイス?Transformer に伝える方法はありますか? 「ほら、出力が単独で正当な XML であるかどうかについて、頭のぼんやりした頭を強調しないでください。単独で解析されることはありません (しかし、あなたはそれを知りません)」 、テキストを生成するだけで、そのコンテキストについて心配させてください」?

4

2 に答える 2

6

引用されたエラー メッセージ「プレフィックス '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>

その前提で、ここに私の提案があります。つまり、「大きな」XML から「モノ」ノードを抽出する必要があります。標準的なアプローチは、XSLT を少し使用してそれを行うことです。以下を使用して XSL 変換を準備します。

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、上記(および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>

「もの」のことを乗り越えてくれることを願っています:)

于 2013-02-14T23:59:01.680 に答える
0

提供されたドキュメントを解析し、Thingノードを取得して、問題なく印刷することができました。

作業例を見てください:

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

nodeToString :

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

@marty が提案したのと同じコードを試してみるCustomAttr:attributeNameと、元の例外で失敗するため、元の XML のどこかで属性またはノードにそのカスタムCustomAttr名前空間をプレフィックスとして付けているように見えます。

後者の場合、 Thingノード自体setNamespaceAware(true)の名前空間情報が含まれるの問題を利用できます。

<?xml version="1.0" encoding="UTF-8"?><Thing xmlns:CustomAttr="http://BlitherBlither" CustomAttr:attributeName="borkborkbork" xmlns="http://BlahBlahBlah"/>
于 2013-02-15T18:40:40.300 に答える