Groovy:如何解析xml并保留命名空间和schemaLocations

问题描述:

我正在尝试使用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

谢谢!

首先,我不得不添加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://*.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

的XmlSlurper(或XMLParser的),如果设置了构造函数的第二个参数不处理命名空间

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

没有namespaceAware设置为false,我也面临解析器的奇怪行为。设置为false后,它保持原样,没有名称空间更改。