2013-03-01 43 views
5

我正在嘗試使用groovy來簡單地將節點添加到特定位置。我的源架構看起來像這樣Groovy:如何解析xml並保留命名空間和schemaLocations

<s1:RootNode 
    xmlns:s1="http://localhost/s1schema" 
    xmlns:s2="http://localhost/s2schema" 
    xsi:schemaLocation="http://localhost/s1schema s1schema.xsd 
    http://localhost/s2schema s2schema.xsd"> 
<s1:aParentNode> 
    <s2:targetNode> 
    <s2:childnode1 /> 
    <s2:childnode2 /> 
    <s2:childnode3 /> 
    <s2:childnode4 /> 
</s2:targetNode> 
</s1:aParentNode> 
</s1:RootNode> 

我想簡單地增加一個新的子節點內嵌在其他的使輸出

<s1:RootNode 
    xmlns:s1="http://localhost/s1schema" 
    xmlns:s2="http://localhost/s2schema" 
    xsi:schemaLocation="http://localhost/s1schema s1schema.xsd 
    http://localhost/s2schema s2schema.xsd"> 
<s1:aParentNode>  
    <s2:targetNode> 
    <s2:childnode1 /> 
    <s2:childnode2 /> 
    <s2:childnode3 /> 
    <s2:childnode4 /> 
    <s2:childnode5 >value</s2:childnode5> 
    </s2:targetNode> 
    </s1:aParentNode> 
</s1:RootNode> 

要做到這一點,我有以下簡單的Groovy腳本

def data = 'value' 
def root = new XmlSlurper(false,true).parseText(sourceXML) 
     root.'aParentNode'.'topNode'.appendNode{ 
      's2:childnode5' data 
     } 
groovy.xml.XmlUtil.serialize(root); 

但是當我這樣做時,應用於根節點的名稱空間和schemaLocations被刪除。和名稱空間,但不會將模式位置添加到每個子節點。

這導致下游驗證問題。

我該如何簡單地處理這個XML。不執行驗證並保留xml,並添加我指定的名稱空間的單個節點?

一個注意事項:我們處理很多消息,並且事先不知道最外層的命名空間(上例中的s1),但即使如此,我真的只是尋找一種「笨蛋」技術,處理xml

謝謝!

回答

2

首先,我不得不添加xmlns:xsi =「http://www.w3.org/2001/XMLSchema-instance」來定義你的xsi命名空間。沒有它,我會收到未綁定的xsi前綴的SAXParseException。

此外,我諮詢了這個question成功將名稱空間xml節點附加到現有文檔。

最後,我們不得不利用StreamingMarkupBuilder來解決命名空間的移動問題。基本上,默認情況下,序列化程序將引用的名稱空間移動到實際使用名稱空間的第一個節點。在你的情況下,它將你的s2名稱空間屬性移動到「targetNode」標籤。以下代碼會生成您想要的結果,但您仍然必須知道用於實例化StreamingMarkupBuilder的正確名稱空間。

XmlSlurper (boolean validating, boolean namespaceAware) 

爲false:

def root = new XmlSlurper(false, true).parseText(sourceXML) 
def data = '<s2:childnode5 xmlns:s2="http://localhost/s2schema">value</s2:childnode5>' 
def xmlFragment = new XmlSlurper(false, true).parseText(data) 
root.'aParentNode'.'targetNode'.appendNode(xmlFragment); 

def outputBuilder = new StreamingMarkupBuilder() 
String result = XmlUtil.serialize(outputBuilder.bind { 
    mkp.declareNamespace('s1':"http://localhost/s1schema") 
    mkp.declareNamespace('s2':"http://localhost/s2schema") 
    mkp.yield root } 
) 
+0

此問題也涉及一些相同的問題:http://stackoverflow.com/questions/227447/how-do-i-print-a-groovy-node-with-namespace-preserved – purgatory101 2013-03-01 23:01:32

+0

謝謝。我偶然發現了這樣的解決方案,我唯一的問題是,我不知道哪個schemata被定義或需要在處理之前被定義,所以我將無法'mkp.declareNamespace(..)'此外,我們需要能夠處理對模式的更改,而無需更改此組件。所以我唯一的答案是將這些模式定義爲某個映射,或者在執行工作之前從xml解析它們。雖然它的代碼行數略多,但使用DOM解析java中的xml似乎更明顯 – Beta033 2013-03-04 15:37:20

0

的XmlSlurper(或XMLParser的),如果設置了構造函數的第二個參數不處理命名空間

def root = new XmlSlurper(false, false).parseText(sourceXML) 

沒有namespaceAware設置爲false,我也面臨解析器的奇怪行爲。設置爲false後,它保持原樣,沒有名稱空間更改。

相關問題