2009-05-27 15 views
12

Javaで名前空間を含むxpathを解決するには、NamespaceContextオブジェクトを使用し、接頭辞と名前空間URLをマッピングする必要があります。しかし、自分自身で実装する以外には、NamespaceContextを入手するためのメカニズムが見つかりません。これは直感的ではないようです。NamespaceContextとXPathでの名前空間の使用

質問:ドキュメントからNamespaceContextを取得するために、または1つ、または、完全にプレフィックスを断念し、完全修飾名でXPathを指定することができないを作成する簡単な方法はありますか?

+1

あなたの質問から、いくつかの基本的な誤解があります:XPathでXMLからすべての名前空間URIを得ることができますが(SOの答えがあります)、接頭辞 - 名前空間URIバインディングクラスを単純に設定することはできません。 *各ノードに対して**異なる境界になる可能性があります。ノードを選択するときは、事前に必要な要素の名前を知っている必要があります** **名前空間URI ** –

答えて

11

独自のクラスを作成せずにNamespaceContextインスタンスインスタンスを取得することは可能です。そのclass-useページには、javax.xml.streamパッケージを使用して入手できることが示されています。

String ctxtTemplate = "<data xmlns=\"http://base\" xmlns:foo=\"http://foo\" />"; 
NamespaceContext nsContext = null; 

XMLInputFactory factory = XMLInputFactory.newInstance(); 
XMLEventReader evtReader = factory 
    .createXMLEventReader(new StringReader(ctxtTemplate)); 
while (evtReader.hasNext()) { 
    XMLEvent event = evtReader.nextEvent(); 
    if (event.isStartElement()) { 
    nsContext = ((StartElement) event) 
     .getNamespaceContext(); 
    break; 
    } 
} 

System.out.println(nsContext.getNamespaceURI("")); 
System.out.println(nsContext.getNamespaceURI("foo")); 
System.out.println(nsContext 
    .getNamespaceURI(XMLConstants.XMLNS_ATTRIBUTE)); 
System.out.println(nsContext 
    .getNamespaceURI(XMLConstants.XML_NS_PREFIX)); 

前述のプレフィックスは完全に曖昧な表現につながる可能性がある - あなたが名前空間接頭辞をドロップしたい場合は、ドキュメントの書式を変更する必要があると思います。ドキュメントからコンテキストを作成することは必ずしも意味をなさない。プレフィックスは、このコードのように、任意の文書中のもの、XPath式で使用されるものではないと一致する必要があります。

String xml = "<data xmlns=\"http://base\" xmlns:foo=\"http://foo\" >" 
    + "<foo:value>" 
    + "hello" 
    + "</foo:value>" 
    + "</data>"; 
String expression = "/stack:data/overflow:value"; 
class BaseFooContext implements NamespaceContext { 
    @Override 
    public String getNamespaceURI(String prefix) { 
    if ("stack".equals(prefix)) 
     return "http://base"; 
    if ("overflow".equals(prefix)) 
     return "http://foo"; 
    throw new IllegalArgumentException(prefix); 
    } 

    @Override 
    public String getPrefix(String namespaceURI) { 
    throw new UnsupportedOperationException(); 
    } 

    @Override 
    public Iterator<String> getPrefixes(
     String namespaceURI) { 
    throw new UnsupportedOperationException(); 
    } 
} 
XPathFactory factory = XPathFactory.newInstance(); 
XPath xpath = factory.newXPath(); 
xpath.setNamespaceContext(new BaseFooContext()); 
String value = xpath.evaluate(expression, 
    new InputSource(new StringReader(xml))); 
System.out.println(value); 

のStAX APIによって返された実装でも上記1のいずれもがフルclass/methodを実装します文書に定義されている契約。完全な地図ベースの実装hereを得ることができます。

+0

が含まれています。自分でクラスを実装しない限り、任意のマッピングを行うNamespaceContextを持つことはできません。しかしXMLストリームの例では、少なくとも、最初の例のように、マイクロドキュメントを構築する静的関数からNamespaceContextを作成するためのパスを提供しています。私はそれを試みます。 – Jherico

+0

はい、それはデフォルトの実装がないという痛みです。 – McDowell

+0

私はそれが愚かであると提出します。パブリックAPIで使用されるその他のJavaインターフェイスには、公開されている具体的な実装やファクトリがどれくらいありますか? – Jherico

7

私はxpathとNamespaceContextsを使って作業しています。私は問題の良い扱いを見つけたon developerworks

+2

IBMからこのエッセーを読んだ後に、なぜデフォルト実装がないのか理解できます。この問題を解決するにはさまざまな方法があります。つまり、Apacheのようなオープンソースグループでは、さまざまな実装のライブラリを作成できないのはなぜですか? – kevinarpe

6

"Apache WebServices Common Utilities"という便利な実装がNamespaceContextImplと呼ばれています。

あなたはこのクラス取得するには、次のMavenの依存関係を使用することができます。

<dependency> 
    <groupId>org.apache.ws.commons</groupId> 
    <artifactId>ws-commons-util</artifactId> 
    <version>1.0.1</version> 
</dependency> 

を私は次のようにそれを使用しました(私が知っているそのサックスのために構築されますが、コード、その[OK]を読んだ後):

NamespaceContextImpl nsContext = new NamespaceContextImpl(); 
nsContext.startPrefixMapping("foo", "my.name.space.com"); 

endPrefixMappingを呼び出す必要はありません。

+1

あなたはまだ名前空間をハードコーディングしています! – Meitham

+0

私が探していたものとまったく同じです。 javadoc:http://ws.apache.org/commons/util/apidocs/index.html –

+0

Meitham - 名前空間のハードコーディングを避ける方法はありません。この名前空間コンテキストを作成し、短い接頭辞を文書に含まれている*それぞれの名前空間*にマッピングしてXPath検索をブートストラップしています。そして、XPathで検索するときにパスを定義するときに接頭辞を使用します。 –

1

あなたは彼らのNamespaceContext実装 org.springframework.util.xml.SimpleNamespaceContext

これはアサフMesikaから1のような同様の答えである再利用することができSpringフレームワークを使用している場合。したがって、ドキュメントに基づいて自動的にNamespaceContextを提供するわけではありません。あなたはそれを自分で構築する必要があります。それでも、それはあなたが少なくともあなたの実装を開始するので、あなたを助けます。

同様の問題に直面したときには、スプリングSimpleNamespaceContextと「Apache WebServices Common Utilities」の両方が機能しました。私たちはApache WebServices Common Utilitiesへの追加jarの依存性を避け、Springベースのアプリケーションを使用していました。

0

あなたがJersey 2を使用して、デフォルトのXML名前空間(xmlns="...")を持っている場合は、あなたがSimpleNamespaceResolverを使用することができます。

<?xml version="1.0" encoding="UTF-8"?> 
<Outer xmlns="http://host/namespace"> 
    <Inner /> 
</Outer> 
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); 
docBuilderFactory.setNamespaceAware(true); 
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); 

Document document = docBuilder.parse(new File("document.xml")); 
String query = "/t:Outer/t:Inner"; 

XPath xpath = XPathFactory.newInstance().newXPath(); 
String xmlns = document.getDocumentElement().getAttribute("xmlns"); 
xpath.setNamespaceContext(new SimpleNamespaceResolver("t", xmlns)); 

NodeList nodeList = (NodeList) xpath.evaluate(query, document, XPathConstants.NODESET); 

//nodeList will contain the <Inner> element 

したい場合は、手動でもxmlnsを指定することができます。