【问题标题】:How to parse advanced XML files in Java如何在 Java 中解析高级 XML 文件
【发布时间】:2025-11-20 15:35:03
【问题描述】:

我看过很多关于如何在 Java 中读取 XML 文件的示例。但它们只显示简单的 XML 文件。例如,他们展示了如何从 XML 文件中提取名字和姓氏。但是我需要从 collada XML 文件中提取数据。像这样:

<library_visual_scenes>
    <visual_scene id="ID1">
        <node name="SketchUp">
            <instance_geometry url="#ID2">
                <bind_material>
                    <technique_common>
                        <instance_material symbol="Material2" target="#ID3">
                            <bind_vertex_input semantic="UVSET0" input_semantic="TEXCOORD" input_set="0" />
                        </instance_material>
                    </technique_common>
                </bind_material>
            </instance_geometry>
        </node>
    </visual_scene>
</library_visual_scenes>

这只是 collada 文件的一小部分。这里我需要提取visual_scene的id,然后是instance_geometry的url,最后是instance_material的target。当然我需要提取更多,但我不明白如何真正使用它,这是一个开始的地方。

到目前为止我有这个代码:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
    builder = factory.newDocumentBuilder();
}
catch( ParserConfigurationException error ) {
    Log.e( "Collada", error.getMessage() ); return;
}
Document document = null;
try {
    document = builder.parse( string );
}
catch( IOException error ) {
    Log.e( "Collada", error.getMessage() ); return;
}
catch( SAXException error ) {
    Log.e( "Collada", error.getMessage() ); return;
}
NodeList library_visual_scenes = document.getElementsByTagName( "library_visual_scenes" );

似乎网络上的大多数示例都与此类似:http://www.easywayserver.com/blog/java-how-to-read-xml-file/

当我想提取更深层次的标签或找到关于阅读/解析 XML 文件的好教程时,我需要帮助弄清楚该怎么做。

【问题讨论】:

标签: java xml collada


【解决方案1】:

真的,当您调用builder.parse(string) 时,您的解析 本身已经完成。你现在需要知道的是如何从解析后的 XML 文档中选择/查询信息。

我同意@khachik 关于如何做到这一点。详细说明(因为没有其他人发布答案):

XPath 是提取信息最方便的方法,如果您的输入文档不大,XPath 也足够快。 Here 是一个很好的 Java XPath 入门教程。如果您需要随机访问 XML 数据(即,如果您必须以与源文档中出现的顺序不同的顺序来回从树中提取数据),也建议使用 XPath,因为 SAX 是为线性访问而设计的。

一些示例 XPath 表达式:

  • 提取visual_scene的id:/*/visual_scene/@id
  • instance_geometry的url:/*/visual_scene/node/instance_geometry/@url
  • 名称为 Sketchup 的节点的 instance_geometry 的 url:/*/visual_scene/node[@name = 'Sketchup']/instance_geometry/@url
  • instance_material 的目标:/*/visual_scene/node/instance_geometry/bind_material/technique_common/instance_material/@target

由于 COLLADA 模型可能非常大,您可能需要执行基于 SAX 的过滤器,这将允许您以流模式处理文档,而不必一次将其全部保存在内存中。但是,如果解析 XML 的现有代码已经足够好,则可能不需要 SAX。使用 SAX 提取特定数据比 XPath 更复杂。

【讨论】:

    【解决方案2】:

    您在代码中使用 DOM。
    DOM 会创建它解析的 xml 文件的树形结构,你必须遍历树才能获取各个节点中的信息。
    在您的代码中,您所做的就是创建树表示。 IE。

    document = builder.parse( string );//document is loaded in memory as tree  
    

    现在您应该参考 DOM api 来了解如何获取您需要的信息。

    NodeList library_visual_scenes = document.getElementsByTagName( "library_visual_scenes" );
    

    例如,此方法返回具有指定名称的所有元素的 NodeList。
    现在你应该遍历 NodeList

     for (int i = 0; i < library_visual_scenes.getLength(); i++) {
       Element element = (Element) nodes.item(i);
       Node visual_scene = element.getFirstChild();
       if(visual_scene.getNodeType() == Node.ELEMENT_NODE)
       {
          String id = ((Element)visual_scene).getAttribute(id);
          System.out.println("id="+id);
        }
     }
    

    免责声明:这是一个示例代码。没有编译它。它向您展示了这个概念。您应该查看 DOM api。

    【讨论】:

    • 我要给 DOM 一个机会。主要是因为这就是我开始的方式,而且看起来很容易。我还发现了一个不错的基础教程:roseindia.net/xml/dom
    【解决方案3】:

    EclipseLink JAXB (MOXy) 有一个有用的@XmlPath 扩展,用于利用 XPath 填充对象。这可能是您正在寻找的东西。注意:我是 MOXy 技术负责人。

    以下示例将一个简单的地址对象映射到 Google 的地理编码信息表示:

    package blog.geocode;
    
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.XmlType;
    
    import org.eclipse.persistence.oxm.annotations.XmlPath;
    
    @XmlRootElement(name="kml")
    @XmlType(propOrder={"country", "state", "city", "street", "postalCode"})
    public class Address {
    
        @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:Thoroughfare/ns:ThoroughfareName/text()")
        private String street;
    
        @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:LocalityName/text()")
        private String city;
    
        @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:AdministrativeAreaName/text()")
        private String state;
    
        @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:CountryNameCode/text()")
        private String country;
    
        @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:PostalCode/ns:PostalCodeNumber/text()")
        private String postalCode;
    
    }
    

    有关示例的其余部分,请参阅:

    【讨论】:

      【解决方案4】:

      如今,一些 Java RAD 工具具有来自给定 DTD 的 Java 代码生成器,因此您可以使用它们。

      【讨论】: