2014-02-14 55 views
6

我當前的代碼是打印出像這樣的XML:命名空間和JDOM

<type xmlns="http://www.example.com"> 
    <OBJECT_TYPE xmlns="">x3000</OBJECT_TYPE> 
- <prop xmlns=""> 
    <DESCRIPTION>a very fast train</DESCRIPTION> 
    <PARENT>NULL</PARENT> 
    <VIRTUAL>0</VIRTUAL> 
    <VISIBLE>1</VISIBLE> 
    <PICTURE>NULL</PICTURE> 
    <HELP>NULL</HELP> 
    <MIN_NO>NULL</MIN_NO> 
    <MAX_NO>NULL</MAX_NO> 
    <NAME_FORMAT>NULL</NAME_FORMAT> 
    </prop> 
</type> 

但我想這樣的輸出:

<type xmlns="http://www.example.com"> 
    <OBJECT_TYPE>x3000</OBJECT_TYPE> 
- <prop> 
    <DESCRIPTION>a very fast train</DESCRIPTION> 
    <PARENT>NULL</PARENT> 
    <VIRTUAL>0</VIRTUAL> 
    <VISIBLE>1</VISIBLE> 
    <PICTURE>NULL</PICTURE> 
    <HELP>NULL</HELP> 
    <MIN_NO>NULL</MIN_NO> 
    <MAX_NO>NULL</MAX_NO> 
    <NAME_FORMAT>NULL</NAME_FORMAT> 
    </prop> 
</type> 

如何做到這一點?這是我當前的代碼:

public void saveXmlToFile(Type objType, Properties property) 
    throws IOException, ParserConfigurationException, SAXException, 
    JDOMException { 

     File xmlFile = new File(XMLEditorService.getXMLEditorService() 
       .getFile()); 
     org.jdom2.Document doc = new SAXBuilder().build(xmlFile); 
     Element root = doc.getRootElement(); 
     Namespace ns = Namespace.getNamespace("http://www.example.com"); 
     Element type = new Element("type"); 
     Element prop = new Element("prop"); 

     // Add <type> as a child of <root> 
     root.addContent(type); 

     // Set namespace on <type> 
     type.setNamespace(ns); 

     type.addContent(new Element("OBJECT_TYPE").setText(objType.getObjectType())); 

     // Turn off namespace on <prop> 
     prop.setNamespace(Namespace.NO_NAMESPACE); 

     // Add <prop> as a child of <type> 
     type.addContent(prop); 

     prop.addContent(new Element("DESCRIPTION").setText(property.getDescription())); 
     prop.addContent(new Element("PARENT").setText(property.getParent())); 
     prop.addContent(new Element("VIRTUAL").setText(property.getVirtual())); 
     prop.addContent(new Element("VISIBLE").setText(property.getVisible())); 
     prop.addContent(new Element("PICTURE").setText(property.getPicture())); 
     prop.addContent(new Element("HELP").setText(property.getHelp())); 
     prop.addContent(new Element("MIN_NO").setText(property.getMin_no())); 
     prop.addContent(new Element("MAX_NO").setText(property.getMax_no())); 
     prop.addContent(new Element("NAME_FORMAT").setText(property.getName_format())); 

     XMLOutputter xmlOutput = new XMLOutputter(Format.getPrettyFormat()); 
     // Create a new file and write XML to it 
     xmlOutput.output(doc, new FileOutputStream(new File(XMLEditorService.getXMLEditorService().getFile()))); 
     System.out.println("Wrote to file"); 

} 

回答

7

在XML文檔中,如果添加xmlns="http://a.b.c"一個元素,那麼該元素,並且它的所有後代Elements,將在命名空間"http://a.b.c",除非後代元素髮生改變xmlns聲明。這意味着,在XML文檔中,默認命名空間'級聯'到後代。這個過程是一種'方便',因此XML不會「混亂」。 '默認'命名空間是沒有前綴的命名空間。將默認名稱空間設置爲某個值"http://a.b.c"的父元素的子元素即使在該名稱空間中也是'in',即使它們的標記行上沒有xmlns="http://a.b.c"聲明。

當JDOM模擬這樣的文檔時,它將每個元素節點的名稱空間設置爲它應該的確切值。它不會「計算」或「級聯」元素的名稱空間。在JDOM中,如果更改父元素的名稱空間,它也不會更改子元素的名稱空間。因此,舉例來說,如果您有:

<root xmlns="http://a.b.c"> 
    <child /> 
</root> 

然後,你必須在默認的命名空間"http://a.b.c"rootchild。該文件可以創建,在JDOM,如:

Namesapce ns = Namespace.get("http://a.b.c"); 
Element root = new Element("root", ns); 
Element child = new Element("child", ns); 
root.addConent(child); 

注意NS是如何加入到這兩個元素。這個JDOM的輸出會是這樣,因爲expeced:

<root xmlns="http://a.b.c"> 
    <child /> 
</root> 

現在,如果你改變了root的命名空間:

Namesapce ns = Namespace.get("http://a.b.c"); 
Element root = new Element("root", ns); 
Element child = new Element("child", ns); 
root.addConent(child); 
root.setNamespace(Namespace.NO_NAMESPACE); 

您將獲得:

<root> 
    <child xmlns="http://a.b.c"/> 
</root> 

不過,更有趣,如果您離開根名稱空間,並更改子名稱空間,請更改子名稱空間,

Namesapce ns = Namespace.get("http://a.b.c"); 
Element root = new Element("root", ns); 
Element child = new Element("child", ns); 
root.addConent(child); 
child.setNamespace(Namespace.NO_NAMESPACE); 

你:

<root xmlns="http://a.b.c"> 
    <child xmlns="" /> 
</root> 

當你沒有命名空間的說法new Element("tag")而不是new Element("tag", Namespace)然後JDOM會自動把新的元素在NO_NAMESPACE命名空間(同new Element("tag", Namespace.NO_NAMESPACE);)創建JDOM元素。這就是你在做什麼。

因此,JDOM正在做你要求它做的事......但你要求它做的事情看起來並不是你想要的。

你想要什麼,你說的是:

<type xmlns="http://www.example.com"> 
    <OBJECT_TYPE>x3000</OBJECT_TYPE> 
- <prop> 
    <DESCRIPTION>a very fast train</DESCRIPTION> 
    <PARENT>NULL</PARENT> 
    <VIRTUAL>0</VIRTUAL> 
    <VISIBLE>1</VISIBLE> 
    <PICTURE>NULL</PICTURE> 
    <HELP>NULL</HELP> 
    <MIN_NO>NULL</MIN_NO> 
    <MAX_NO>NULL</MAX_NO> 
    <NAME_FORMAT>NULL</NAME_FORMAT> 
    </prop> 
</type> 

上述XML具有一切在命名空間Namespace.getNamespace("http://www.example.com")

您的代碼將許多事情放入NO_NAMESPACE命名空間中。您的代碼可能應該是這樣的(注意,所有的, ns我已經加入到new Element(...))...

Element(String)的JavaDoc,和Element(String, Namespace);

org.jdom2.Document doc = new SAXBuilder().build(xmlFile); 
    Element root = doc.getRootElement(); 
    Namespace ns = Namespace.getNamespace("http://www.example.com"); 
    Element type = new Element("type", ns); 
    Element prop = new Element("prop", ns); 

    // Add <type> as a child of <root> 
    root.addContent(type); 

    // Set namespace on <type> 
    // type.setNamespace(ns); NO NEED, done on new Element("type", ns); above 

    type.addContent(new Element("OBJECT_TYPE", ns).setText(objType.getObjectType())); 

    // Turn off namespace on <prop> 
    // NO!!!! You want to keep the namespace ON!!! 
    // prop.setNamespace(Namespace.NO_NAMESPACE); 

    // Add <prop> as a child of <type> 
    type.addContent(prop); 

    prop.addContent(new Element("DESCRIPTION", ns).setText(property.getDescription())); 
    prop.addContent(new Element("PARENT", ns).setText(property.getParent())); 
    prop.addContent(new Element("VIRTUAL", ns).setText(property.getVirtual())); 
    prop.addContent(new Element("VISIBLE", ns).setText(property.getVisible())); 
    prop.addContent(new Element("PICTURE", ns).setText(property.getPicture())); 
    prop.addContent(new Element("HELP", ns).setText(property.getHelp())); 
    prop.addContent(new Element("MIN_NO", ns).setText(property.getMin_no())); 
    prop.addContent(new Element("MAX_NO", ns).setText(property.getMax_no())); 
    prop.addContent(new Element("NAME_FORMAT", ns).setText(property.getName_format())); 

    XMLOutputter xmlOutput = new XMLOutputter(Format.getPrettyFormat()); 
    // Create a new file and write XML to it 
    xmlOutput.output(doc, new FileOutputStream(new File(XMLEditorService.getXMLEditorService().getFile()))); 
    System.out.println("Wrote to file"); 

在上面的代碼,一切是在"http://www.example.com"命名空間,並且,其結果是,JDOM只需要輸出的頂級元素與xmlns聲明,你應該得到你想要什麼。

對於它的價值,您不僅可以將JDOM歸咎於這種困惑......它是名稱空間的本質,它是複雜的。

+0

你沒有像代碼中那樣將',ns'添加到所有'prop.addContent(....)'中,是嗎? – rolfl

+0

你好。這對我所做的事情起到了反作用。這個解釋值得大量upvotes。我曾經在Stackoverflow上閱讀過的最好的一篇:-) – Sembrano

+1

@Sembrano它幫助我寫了一段代碼....前幾天,當我詢問更多信息時,你應該一直在幫助我;-)而不是刪除你的問題,你可以爲自己節省大量的壓力。 – rolfl