1

对 Java 并不陌生;但对于 XML 解析来说相对较新。我对那里的许多 XML 工具知之甚少,但对它们中的任何一个都知之甚少。我也不是 XML 专业人士。

我的特殊问题是……我得到了一个无法修改的 XML 文档,我只需要将它的随机位解析为 Java 对象。只要它是合理的,纯粹的速度并不是一个很大的因素。同样,内存占用空间也不必是绝对最优的,只要不是疯狂的。我只需要通读一次文档来解析它,然后我将把它扔到 bitbucket 中并使用我的 POJO。

所以,我愿意接受建议……您会使用哪种工具?
而且,您能否建议一些入门代码来满足我的特殊需求?

这是我正在尝试制作的示例 XML 和相关 POJO 的片段:

<xml>
  <item id="...">
    ...
  </item>
  <metadata>
    <resources>

      <resource>
        <ittype>Service_Links</ittype>
        <links>
          <link>
            <path>http://www.stackoverflow.com</path>
            <description>Stack Overflow</description>
          </link>
          <link>
            <path>http://www.google.com</path>
            <description>Google</description>
          </link>
        </links>
      </resource>

      <resource>
        <ittype>Article_Links</ittype>
        <links>
          ...
        </links>
      </resource>

      ...

    </resources>
  </metadata>
</xml>


public class MyPojo {

    @Attribute(name="id")
    @Path("item")
    public String id;

    @ElementList(entry="link")
    @Path("metadata/resources/resource/links")
    public List<Link> links;
}

注意:这个问题最初是由这个问题产生的,我试图使用 SimpleXml 解决它;我到了我认为也许有人可以提出解决同一问题的不同途径的地步。

另请注意:我真的希望有一个CLEAN解决方案......我的意思是,使用注释和/或 xpath 以及最少的代码......我想要的最后一件事是具有巨大笨拙方法的巨大类文件...... . 那个,我已经... 我正在努力寻找更好的方法。

:D

4

3 回答 3

1

好的,所以我确定了一个(对我而言)似乎以最合理的方式满足我的需求的解决方案。我对其他建议表示歉意,但我只是更喜欢这条路线,因为它将大部分解析规则保留为注释,而我必须编写的少量程序代码非常少。

我最终选择了 JAXB;最初我认为 JAXB 要么从 Java 类创建 XML,要么将 XML 解析为 Java 类,但只能使用 XSD。然后我发现 JAXB 有注释,可以将 XML 解析为 Java 类而无需 XSD。

我正在使用的 XML 文件很大而且很深,但我只需要这里和那里的一点点;我担心将来将地图导航到哪里会非常困难。所以我选择构建一个以 XML 为模型的文件夹树……每个文件夹映射到一个元素,每个文件夹中都有一个 POJO 代表该实际元素。

问题是,有时有一个元素有几个级别的子元素,它有一个我关心的属性。仅仅为了访问一个属性而创建 4 个嵌套文件夹和一个 POJO 会很痛苦。但这就是您使用 JAXB 的方式(至少,据我所知);我又一次在角落里。

然后我偶然发现了EclipseLink 的 JAXB 实现:Moxy。Moxy 有一个 @XPath 注释,我可以将其放置在该父 POJO 中,并用于向下导航几个级别以访问单个属性,而无需创建所有这些文件夹和元素 POJO。好的。

所以我创建了这样的东西:(注意:我选择在需要按摩值的情况下使用吸气剂)

// maps to the root-"xml" element in the file
@XmlRootElement( name="xml" )
@XmlAccessorType( XmlAccessType.FIELD )
public class Xml {

    // this is standard JAXB
    @XmlElement;               
    private Item item;
    public Item getItem() {    
        return this.item;
    }

    ...
}

// maps to the "<xml><item>"-element in the file
public class Item {

    // standard JAXB; maps to "<xml><item id="...">"
    @XmlAttribute              
    private String id;
    public String getId() {
        return this.id;
    }

    // getting an attribute buried deep down
    // MOXY; maps to "<xml><item><rating average="...">"
    @XmlPath( "rating/@average" )    
    private Double averageRating;
    public Double getAverageRating() {
        return this.average;
    }

    // getting a list buried deep down
    // MOXY; maps to "<xml><item><service><identification><aliases><alias.../><alias.../>"
    @XmlPath( "service/identification/aliases/alias/text()" )
    private List<String> aliases;
    public List<String> getAliases() {
        return this.aliases;
    }

    // using a getter to massage the value
    @XmlElement(name="dateforindex")
    private String dateForIndex;
    public Date getDateForIndex() {
        // logic to parse the string-value into a Date
    }

}

另请注意,我将 XML 对象与我在应用程序中实际使用的模型对象分开。因此,我有一个工厂,可以将这些原始对象转换为我在我的应用程序中实际使用的更强大的对象。

于 2012-11-05T16:22:08.497 回答
0

如果您的 XML 文档相对较小(如这里所示),我将使用 DOM 框架和 XPath 类。这是我的一个教程中的一些样板 DOM/XPath 代码

File xmlFile = ...
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(xmlFile);

XPath xp = XPathFactory.newInstance().newXPath();
String value = xp.evaluate("/path/to/element/text()", doc);
// .. reuse xp to get other values as required

换句话说,基本上你:

  • 通过 DocumentBuilder 将您的 XML 转换为 Document 对象;

  • 创建一个 XPath 对象;

  • 重复调用 XPath.evaluate(),传入所需元素的路径和您的 Document。

如您所见,在获取 Document 对象时有一点复杂性,并且与所有优秀的 XML API 一样,它会引发大量愚蠢且无意义的检查异常。但除此之外,对于结构相对固定的简单中小型 XML 文档的解析是相当严肃的。

于 2012-10-08T23:52:49.380 回答
0

您可以使用 SAXParser 或 STAXParser。如果您能负担得起更多的内存,那么您也可以负担得起使用 DOMParser。我建议 STAXParser 最适合你。

于 2012-10-09T08:11:34.077 回答