建议用Java解析这个XML

时间:2012-10-08 22:57:50

标签: java xml xpath xml-parsing

不是Java新手;但是XML解析相对较新。我对那里的许多XML工具有一点了解,但对它们中的任何一个都没有多少。我也不是XML-pro。

我的特殊问题是这个...我得到了一个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;
}

注意:这个问题最初由this question产生,我尝试使用SimpleXml解决它;我想到也许有人可以建议一条不同的路线去解决同样的问题。

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

:d

3 个答案:

答案 0 :(得分:1)

好的,所以我找到了一个解决方案(对我来说)似乎以最合理的方式解决了我的需求。我对其他建议表示道歉,但我更喜欢这条路线,因为它将大部分解析规则作为注释,而我必须编写的程序代码很少。

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

我正在使用的XML文件非常庞大且非常深入,但我只需要点到点就可以了;我担心将导航到未来的地方非常困难。所以我选择构建一个以XML格式建模的文件夹树...每个文件夹映射到一个元素,每个文件夹中都有一个表示该实际元素的POJO。

问题是,有时会有一个元素,它有一个子元素,有几个级别,它有一个我关心的属性。为每个属性创建4个嵌套文件夹和POJO只是为了访问单个属性会很麻烦。但这就是你用JAXB做的事情(至少,从我能说的);我又一次在角落里。

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

所以我创建了这样的东西: (注意:我选择使用getter来处理需要按摩值的情况)

// 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对象与我在应用程序中实际使用的模型对象分开的路径。因此,我有一个工厂将这些原始对象转换为更强大的对象,我实际上在我的应用程序中使用它。

答案 1 :(得分:0)

如果您的XML文档相对较小(如此处所示),我将使用DOM框架和XPath类。以下是我的一个教程中的一些boilerplate DOM/XPath code

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对象并且像所有优秀的XML API一样,有一点点狡猾,它引发了大量愚蠢无意义的检查异常。但除此之外,解析结构相对固定的简单的中小型XML文档是相当没有意义的。

答案 2 :(得分:0)

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