名称空间和JDOM

时间:2014-02-14 12:06:55

标签: java xml namespaces jdom

我当前的代码是打印出xml,如下所示:

<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");

}

1 个答案:

答案 0 :(得分:7)

在XML文档中,如果向元素添加xmlns="http://a.b.c",那么该元素及其所有后代元素将位于命名空间"http://a.b.c"中,除非后代元素恰好更改{ {1}}声明。这意味着,在XML文档中,默认命名空间“级联”到后代。这个过程是一个“便利”,因此XML不会“混乱”。 'default'命名空间是没有前缀的命名空间。将默认命名空间设置为某个值xmlns的父项的子元素是'在'该命名空间中,即使它们的标记行上没有"http://a.b.c"声明。

当JDOM为这样的文档建模时,它会将每个Element节点的Namespace设置为它应该具有的确切值。它不会“计算”或“级联”元素的命名空间。在JDOM中,如果更改父元素的命名空间,它也不会更改子元素的命名空间。所以,例如,如果你有:

xmlns="http://a.b.c"

然后,您在默认的命名空间<root xmlns="http://a.b.c"> <child /> </root> 中同时拥有rootchild。该文档可以在JDOM中创建为:

"http://a.b.c"

注意ns是如何添加到两个元素的。这个JDOM的输出将如下所示:

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

现在,如果您更改root的命名空间:

<root xmlns="http://a.b.c">
    <child />
</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")的JDOM元素时,JDOM会自动将新元素放入NO_NAMESPACE名称空间(与new Element("tag", Namespace)相同)。这就是你在做什么。

所以,JDOM正在做你要求它做的事情......但你要求它做的事情似乎并不像你想要的那样。

你说你想要的是:

new Element("tag", Namespace.NO_NAMESPACE);

上述XML在命名空间<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> 中包含所有内容

您的代码将大量内容放入NO_NAMESPACE命名空间中。您的代码可能看起来像这样(请注意我添加到Namespace.getNamespace("http://www.example.com")的所有, ns)...

请参阅JavaDoc以了解Element(String)Element(String, Namespace);

new Element(...)

在上面的代码中,一切位于 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"); 命名空间中,因此,JDOM只需要输出带有"http://www.example.com"声明的顶级元素,你应该得到你想要的。

对于它的价值,你不仅可以将JDOM归咎于这种混乱......它是命名空间的本质,它很复杂。