2016-07-06 5 views
3

現在、JAXBを使用してJava POJOからXMLにマップされているオブジェクトがあります。そのXMLを取得したら、ユーザーの入力に基づいて選択された要素のセットのみに絞る必要があることがあります。結果は指定された "フィールド"のみを持つXMLでなければなりません。GroovyまたはJavaの要素「パス」でXML文字列をフィルタリングする方法

私はSAXフィルタを使用した類似の使用例を数多く見つけましたが、それらは非常に複雑に見えますが、回答が必要な場所に届きません。最も近い例はthis oneであり、結果から単一のパスは除外されます。反対のホワイトリストに選択された要素のリストが必要です。

例オブジェクト:School.xml

<SchoolInfo RefId="34060F68BE3942F1B1264E6D2CC3C353"> 
     <LocalId>57</LocalId> 
     <SchoolName>Foobar School of Technology</SchoolName> 
     <Principal> 
      <FirstName>Bob</FirstName> 
      <LastName>Smith</LastName> 
     </Principal> 
     <StateProvinceId>34573</StateProvinceId> 
     <LEAInfoRefId>340666687E3942F1B1264E1223453C353</LEAInfoRefId> 
     <PhoneNumberList> 
      <PhoneNumber Type="0096"> 
       <Number>555-832-5555</Number> 
      </PhoneNumber> 
      <PhoneNumber Type="0096"> 
       <Number>555-999-5555</Number> 
      </PhoneNumber> 
     </PhoneNumberList> 
    </SchoolInfo> 

は、 "フィルタ" として、次の入力を考える:

List<String> filter = [ 
    "LocalId", 
    "SchoolName", 
    "Principal/FirstName", 
    "PhoneNumberList/PhoneNumber/Number", 
] 

Iが出力する必要がありますは何

<SchoolInfo RefId="34060F68BE3942F1B1264E6D2CC3C353"> 
    <LocalId>57</LocalId> 
    <SchoolName>Foobar School of Technology</SchoolName> 
    <Principal> 
     <FirstName>Bob</FirstName> 
    </Principal> 
    <PhoneNumberList> 
     <PhoneNumber Type="0096"> 
      <Number>555-832-5555</Number> 
     </PhoneNumber> 
     <PhoneNumber Type="0096"> 
      <Number>555-999-5555</Number> 
     </PhoneNumber> 
    </PhoneNumberList> 
</SchoolInfo> 

これを達成するための最良のライブラリですか? SAXフィルタリングは複雑に感じられ、XSLTは動的フィルタリングに適していないようです。

私が近づくのを助ける例は高く評価されます。

+0

は 'Groovy'は' XmlParser'または 'MarkupBuild'と良いことがあります。 [here](http://mrhaki.blogspot.in/2011/05/groovy-goodness-change-xml-structure.html)のサンプルを参照してください。 – Rao

+1

これを実行するコードサンプルを探しているのか、単にlibsの推奨を求めていますか? –

+0

@ vtd-xml-authorコードサンプルは素晴らしかったですが、誰かに私のために作業を依頼しているわけではありません。使用する適切なライブラリに関するアドバイスとそのライブラリ内のメソッドが私が探しているものです。 –

答えて

0

これは、XPathとVTD-XMLに基づいています。その出力インデントの問題を持っている...これは...正しさを強調している最初のパスである

import com.ximpleware.*; 
import java.io.*; 
import java.util.*; 

public class whiteList { 

    public static void main(String[] s) throws VTDException, IOException{ 
     VTDGen vg = new VTDGen(); 
     List <String> filter = Arrays.asList("LocalId", 
       "SchoolName", 
       "Principal/FirstName", 
       "PhoneNumberList/PhoneNumber/Number"); 
     if (!vg.parseFile("d:\\xml\\schoolInfo.xml", false)){ 
      return; 
     } 
     VTDNav vn = vg.getNav(); 
     FastIntBuffer fib = new FastIntBuffer(); 
     // build a bitmap for the entire token pool consisting of elements 
     int i,k; 
     for (i=0;i<vn.getTokenCount();i++){ 
      if (vn.getTokenType(i)==VTDNav.TOKEN_STARTING_TAG){ 
       fib.append(0x1);// b'11 since it is a white list, 
      }else{ 
       fib.append(0); 
      } 
     } 
     AutoPilot ap = new AutoPilot(vn); 
     AutoPilot ap1= new AutoPilot(vn); 
     ap1.selectXPath("descendant::*");// mark descendant as keep 
     for (int j=0;j<filter.size();j++){ 
      ap.selectXPath(filter.get(j)); 
      while((i=ap.evalXPath())!=-1){ 
       fib.modifyEntry(i, 0x3); 
       vn.push(); 
       do{ 
        if(vn.getTokenDepth(vn.getCurrentIndex())>=0) 
         fib.modifyEntry(vn.getCurrentIndex(), 0x3); 
        else 
         break; 
       }while(vn.toElement(VTDNav.P)); 
       vn.pop(); 
       vn.push(); 
       while((k=ap1.evalXPath())!=-1){ 
        fib.modifyEntry(k, 0x3); 
       } 
       ap1.resetXPath(); 
       vn.pop(); 
      } 
      ap.resetXPath(); 
     } 

     //remove those not on the whitelist 
     XMLModifier xm = new XMLModifier(vn); 
     for (int j=0;j<fib.size();j++){ 
      if (fib.intAt(j)==0x1){ 
       vn.recoverNode(j); 
       xm.remove(); 
      } 
     } 
     xm.output("d:\\xml\\newSchoolInfo.xml");      
    } 
} 
+0

私は今これをテストしています。ただちに修正する必要があるのは、Stringから読み込み、Stringとして出力する必要があるということです。私はByteArrayInputStreamとそれに相当するものを使用できると仮定していますか? –

+0

ByteArrayOutputStreamでxm.outputを呼び出すと、実際には私のために 'NullPointerException'が発生します。私は実行の後に苦労しているが、出力を書き込もうとするとVTDトークンがないように見える? –

+0

これまで持っていたコードを投稿できますか?文字列から読み込むには、バイト配列に変換する必要があります(これは簡単です(getBytes))...そして、バイト配列からxmlをパースする方法を示すブログ投稿があります。https:/ /ximpleware.wordpress.com/2016/06/02/parsefile-vs-parse-a-quick-comparison/ –

0

すべてのGroovy:

import groovy.xml.XmlUtil 

def xml = '''<SchoolInfo RefId="34060F68BE3942F1B1264E6D2CC3C353"> 
    <LocalId>57</LocalId> 
    <SchoolName>Foobar School of Technology</SchoolName> 
    <Principal> 
     <FirstName>Bob</FirstName> 
     <LastName>Smith</LastName> 
    </Principal> 
    <StateProvinceId>34573</StateProvinceId> 
    <LEAInfoRefId>340666687E3942F1B1264E1223453C353</LEAInfoRefId> 
    <PhoneNumberList> 
     <PhoneNumber Type="0096"> 
      <Number>555-832-5555</Number> 
     </PhoneNumber> 
     <PhoneNumber Type="0096"> 
      <Number>555-999-5555</Number> 
     </PhoneNumber> 
    </PhoneNumberList> 
</SchoolInfo>''' 

def node = new XmlParser().parseText(xml) 

def whitelist = [ 'LocalId', 'SchoolName', 'Principal/FirstName', "PhoneNumberList/PhoneNumber/Number" ]*.split('/') 

def void loveRemovalMachine(node, whitelist) { 
    def elementNamesToKeep = whitelist*.head() 
    println "Retaining nodes ${elementNamesToKeep} for node $node" 
    def nodesToRemove = node.'*'.findAll { child -> !elementNamesToKeep.contains(child.name()) } 
    nodesToRemove.each { node.remove it } 
    def nextWhitelist = whitelist*.tail().findAll { it } 
    println "Next level: $nextWhitelist" 
    if (!nextWhitelist) { 
     return 
    } 
    // The "*" operator seems to return text nodes...very stupid. 
    node.'*:*'.each { loveRemovalMachine it, nextWhitelist } 
} 

loveRemovalMachine node, whitelist 

XmlUtil.serialize node 
+0

出力: '' '結果:<?xml version =" 1.0 "encoding =" UTF-8 " ?技術の> foobarの学校 ボブ スミス 555から832 -5555 555-999-5555 '' ' –

+0

もちろんこれはJavaで行うことができます。このようなコードサンプルが必要な場合は、アドバイスをお願いします。これは同じ考えです:DOMをクリーンアップする再帰的なメソッドです。 Javaのほうがはるかに冗長になるでしょう。 –

関連する問題