XSLTはJavaで開花します

XSLT(Extensible Stylesheet Language Transformation)だけでは解決できない難しいXML変換の問題に悩まされたことはありませんか?たとえば、5日前より前の日付のノードのみを選択する単純なフィルタースタイルシートを考えてみましょう。XSLTはXMLドキュメントをフィルタリングできると聞いているので、この問題はすぐに解決できると思います。最初のタスクは、情報が元のXMLドキュメントに含まれていない場合、スタイルシート内から今日の日付を取得することです。残念ながら、XSLTだけではこのタスクを完了できません。このような状況では、Java拡張機能を使用して、XSLTコードを単純化し、問題をより迅速に解決できます。

多くのXSLTプロセッサでは、ある種の拡張メカニズムが可能です。仕様では、そうする必要があります。 JavaとXMLの世界で最も広く使用されているXSLTプロセッサは、オープンソースのApacheXalanプロセッサです。 XalanはJavaで記述されており、Javaでの拡張が可能です。多くの開発者は、Xalanの拡張性が強力であると感じています。これは、スタイルシートのコンテキスト内からJavaスキルを利用できるためです。 JSP(JavaServer Pages)、スクリプトレット、およびカスタムタグがHTMLに力を加える方法を検討してください。 Xalan拡張機能は、Java開発者がお気に入りのツールであるJavaにアクセスできるようにすることで、ほぼ同じ方法でスタイルシートに機能を追加します。

この記事では、XSLTスタイルシート内からJavaを使用する方法を示します。まず、Xalanの拡張性を使用して、JDK内の既存のクラスをインスタンス化して使用します。後で、String引数を取り、DOM(ドキュメントオブジェクトモデル)フラグメントをスタイルシートプロセッサに返すXSLT拡張関数を作成する方法を説明します。

XMLドキュメントのスタイル設定がサーバー側の操作になっているため、XSLTはJ2EE(Java 2 Platform、Enterprise Edition)開発者にとって重要です。また、XSLTエンジンのサポートを含むJAXP(XML処理用のJava API)は、J2EE仕様(J2EE 2.6.11)の一部になりました。 XSLTは、初期の段階では、クライアントでXMLのスタイルを設定することを目的としていました。ただし、ほとんどのアプリケーションは、XMLをクライアントに送信する前にXMLのスタイルを設定します。 J2EE開発者にとって、これはXSLTプロセッサがアプリサーバー内で実行される可能性が高いことを意味します。

この記事を続ける前に、XSLTスタイルシートでJava拡張機能を使用すると、移植性が低下することに注意してください。拡張機能はXSLT仕様の一部ですが、実装方法は異なります。Internet Explorerのスタイルシートエンジンなど、Xalan以外のプロセッサでスタイルシートを実行する場合は、拡張機能の使用を絶対に避けてください。

XSLTの弱点

XSLTにはいくつかの弱点があるため、XSLT拡張機能は非常に便利です。XSLTが悪いと言っているのではありません。ただし、XMLドキュメント内のすべてを処理するための最適なツールを提供しているわけではありません。XMLのこのセクションを検討してください。

 XSLTは、他の人が持っているほど使いやすいものではありません...   

上司から、「is n't」のすべてのインスタンスを「isnot」に変換し、共通のラベルをローカライズするようにスタイルシートを変更するように求められたとします。確かに、XSLTはこれらの線に沿って何かをするメカニズムを提供しますよね?違う。 XSLTは、文字列内の単語またはパターンの出現を置き換える簡単な方法を提供しません。ローカリゼーションについても同じことが言えます。これは、標準のXSLT構文では実行できないということではありません。方法はいくつかありますが、私たちが望むほど簡単ではありません。再帰テンプレートを使用してテキスト操作関数を本当に作成したい場合は、私のゲストになってください。

XSLTの主な弱点はテキスト処理です。これは、XMLのレンダリングを目的としているため、合理的と思われます。ただし、XMLコンテンツは完全にテキストであるため、XSLTにはより強力なテキスト処理が必要です。言うまでもなく、スタイルシートの設計者は時々ある程度の拡張性を必要とします。Xalanを使用すると、Javaはこの拡張性を提供します。

XSLT内でJDKクラスを使用する

Xalanの拡張性を利用するためにJavaコードを記述する必要がないことを知って喜ぶかもしれません。Xalanを使用すると、ほとんどすべてのJavaオブジェクトでメソッドを作成および呼び出すことができます。Javaクラスを使用する前に、そのクラスにXSLT名前空間を指定する必要があります。この例"java"では、Javaパッケージ内またはJavaパッケージの下にあるすべてのもの(つまり、JDK全体)の名前空間として宣言しています。


  

今、私たちは何かをする必要があります。小さなXMLドキュメントから始めましょう:

 Javaは流行かもしれないJ.バーク97/11/30  

タイトルが大文字で表示されるように、このXMLのスタイルを設定するように求められました。XSLTを初めて使用する開発者は、XSLT参照を開いてtoUpper()関数を探すだけです。しかし、彼女は参照に1つが欠けていることに気づいてがっかりするでしょう。このtranslate()方法が最善の策ですが、私にはさらに優れた方法がありますjava.lang.String.toUpperCase()。このメソッドを使用するにStringは、タイトルの内容でオブジェクトをインスタンス化する必要があります。Stringタイトル要素のコンテンツを使用して新しいインスタンスを作成する方法は次のとおりです。


  

このname属性は、新しいStringインスタンスへのハンドルを指定します。最初に名前空間とStringクラスへの残りのパスを指定して、コンストラクターを呼び出します。お気づきかもしれませんがStringnew()方法がありません。new()XalanでJavaオブジェクトを構築するために使用します。Javaのnewキーワードに対応しています。new()呼び出されるコンストラクターのバージョンを決定するために指定された引数。これで、JavaStringオブジェクト内にタイトルの内容ができたtoUpperCase()ので、次のようにメソッドを使用できます。


  

これは最初は奇妙に見えるかもしれません。特定のインスタンスでJavaメソッドを使用する場合、最初の引数は、メソッドを呼び出すインスタンスです。明らかに、Xalanはイントロスペクションを使用してこの機能を提供します。

以下に別のトリックがあります。以下を使用して、スタイルシート内の任意の場所に日付と時刻を出力する方法を次に示しますjava.lang.Date


  

これは、2つ以上の言語間で一般的なスタイルシートをローカライズする必要がある人の日を作るものです。を使用java.util.ResourceBundleして、スタイルシート内のリテラルテキストをローカライズできます。XMLには作成者タグがある"Author:"ため、人の名前の横に印刷することをお勧めします。

1つのオプションは、ロケールごとに個別のスタイルシートを作成することです。つまり、英語用、中国語用などです。このアプローチに固有の問題は明らかです。複数のスタイルシートバージョンの一貫性を保つには時間がかかります。また、ユーザーのロケールに基づいて正しいスタイルシートを選択するようにアプリケーションを変更する必要があります。

言語ごとにスタイルシートを複製する代わりに、Javaのローカリゼーション機能を利用できます。の助けを借りてローカライズするResourceBundleことは、より良いアプローチを証明します。XSLT内でResourceBundle、次のようにスタイルシートの先頭にをロードします。


  

ResourceBundleクラスが呼ばれるファイルを見つけることを期待General.propertiesあなたの中にCLASSPATH。バンドルが作成されると、スタイルシート全体で再利用できます。この例では、authorリソースを取得します。


  

奇妙なメソッドシグネチャにもう一度注意してください。通常、ResourceBundle.getString()引数は1つだけです。ただし、XSLT内では、メソッドを呼び出すオブジェクトも指定する必要があります。

独自の拡張機能を作成する

まれに、拡張関数または拡張要素のいずれかの形式で、独自のXSLT拡張を作成する必要がある場合があります。かなり理解しやすい概念である拡張関数の作成について説明します。Xalan拡張関数はすべて、文字列を入力として受け取り、文字列をXSLTプロセッサに返すことができます。拡張機能は、引数としてNodeListsまたはNodesを取り、これらの型をXSLTプロセッサーに返すこともできます。NodesまたはNodeListsを使用すると、拡張関数を使用して元のXMLドキュメントに追加できます。これを実行します。

頻繁に遭遇するテキスト項目の1つのタイプは、日付です。これは、新しいXSLT拡張機能に絶好の機会を提供します。私たちのタスクは、日付が次の形式で印刷されるように記事要素のスタイルを設定することです。

20011月30日 金曜日

標準のXSLTは上記の日付を完了できますか?XSLTはほとんどのタスクを完了できます。実際の日を決定することは難しい部分です。この問題をすばやく解決する1つの方法はjava.text.SimpleDate、拡張関数内でformatクラスを使用して、必要に応じてフォーマットされた文字列を返すことです。ただし、待ってください。その日が太字で表示されていることに注意してください。これにより、最初の問題に戻ります。拡張機能を検討している理由は、元のXMLドキュメントがノードのグループとして日付を構造化できなかったためです。拡張関数が文字列を返す場合でも、日付フィールドの残りの部分とは異なるスタイルを設定することは困難です。少なくともXSLT設計者の観点からは、より便利な形式は次のとおりです。

  11 30 2001  

ここで、XSLT拡張関数を作成し、引数として文字列を取り、次の形式でXMLノードを返します。

  2001年11月30日金曜日  

拡張関数をホストするクラスは、何も実装または拡張しません。クラスを呼び出しますDateFormatter

public class DateFormatter {public static Node format(String date){} 

うわー、簡単すぎるね?Xalan拡張関数のタイプまたはインターフェースに課せられる要件はまったくありません。一般に、ほとんどの拡張関数はString引数としてaを取り、別のを返しStringます。他の一般的なパターンは、拡張関数からorg.w3c.dom.NodeListまたは個々Nodeのを送信または受信することです。JavaタイプをXSLTタイプに変換する方法の詳細については、Xalanのドキュメントを参照してください。

In the code fragment above, the format() method's logic breaks into two parts. First, we need to parse the date string from the original XML document. Then we use some DOM programming techniques to create a Node and return it to the XSLT processor. The body of our format() method implementation reads:

 Document doc = DocumentBuilderFactory.newInstance(). newDocumentBuilder().newDocument(); Element dateNode = doc.createElement("formatted-date"); SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale); df.setLenient(true); Date d = df.parse(date); df.applyPattern("MMMM"); addChild(dateNode, "month", df.format(d)); df.applyPattern("EEEE"); addChild(dateNode, "day-of-week", df.format(d)); df.applyPattern("yyyy"); dateNode.setAttribute("year", df.format(d)); return dateNode; 

dateNode will contain our formatted date values that we return to the stylesheet. Notice that we've utilized java.text.SimpleDateFormat() to parse the date. This allows us to take full advantage of Java's date support, including its localization features. SimpleDateFormat handles the numeric date conversion and returns month and day names that match the locale of the VM running our application.

Remember: the primary purpose of an extension function is simply to allow us access to existing Java functionality; write as little code as possible. An extension function, like any Java method, can use other methods within the same class. To simplify the format() implementation, I moved repetitive code into a small utility method:

private void addChild (Node parent, String name, String text) { Element child = parent.getOwnerDocument().createElement(name); child.appendChild(parent.getOwnerDocument().createTextNode(text)); parent.appendChild(child); } 

Use DateFormatter within a stylesheet

Now that we have implemented an extension function, we can call it from within a stylesheet. Just as before, we need to declare a namespace for our extension function:


  

今回は、拡張関数をホストするクラスへのパスを完全に修飾しました。これはオプションであり、同じパッケージ内で他のクラスを使用するのか、単一の拡張オブジェクトのみを使用するのかによって異なります。フルCLASSPATHを名前空間として宣言するか、パッケージを使用して、拡張関数が呼び出されるクラスを指定できます。fullを指定することによりCLASSPATH、関数を呼び出すときに入力する量が少なくなります。

この関数を利用するにはselect、次のようにタグ内から呼び出すだけです。