Java 如何在使用SAX进行解析时保留未绑定到对象的XML节点
我正在开发一款android应用程序,它与蓝牙摄像头接口。对于存储在相机上的每个剪辑,我们将有关剪辑的一些字段(其中一些用户可以更改)存储在XML文件中 目前,此应用程序是唯一一个将xml数据写入设备的应用程序,但将来,桌面应用程序或iphone应用程序也可能在此处写入数据。我不想假设另一个应用程序也不能有额外的字段(特别是如果他们有一个新版本的应用程序,其中添加了这个版本还不支持的新字段) 所以我要防止的是,我们在另一个应用程序中向这个XML文件添加新字段,然后用户使用android应用程序,它会清除其他字段,因为它不知道这些字段 让我们举一个假设的例子:Java 如何在使用SAX进行解析时保留未绑定到对象的XML节点,java,android,xml,sax,Java,Android,Xml,Sax,我正在开发一款android应用程序,它与蓝牙摄像头接口。对于存储在相机上的每个剪辑,我们将有关剪辑的一些字段(其中一些用户可以更改)存储在XML文件中 目前,此应用程序是唯一一个将xml数据写入设备的应用程序,但将来,桌面应用程序或iphone应用程序也可能在此处写入数据。我不想假设另一个应用程序也不能有额外的字段(特别是如果他们有一个新版本的应用程序,其中添加了这个版本还不支持的新字段) 所以我要防止的是,我们在另一个应用程序中向这个XML文件添加新字段,然后用户使用android应用程序,
<data>
<title>My Title</title>
<date>12/24/2012</date>
<category>Blah</category>
</data>
因此,我使用SAX解析数据并将其存储到片段中。
我只需将字符存储在StringBuilder中,并在到达title、category和date的结束元素时将其写出
我意识到,当我将这些数据写回设备时,如果原始文档中有任何其他标记,它们将不会被写入,因为我只写出我知道的字段
这让我觉得也许SAX是错误的选择,也许我应该使用DOM或其他更容易写出最初存在的任何其他元素的东西
或者,我想我的Clip类可能包含某种通用XML类型(可能是DOM)的ArrayList,在startTag中,我检查元素是否不是预定义的标记之一,如果是,在到达该标记的末尾之前,我存储整个结构(但存储在什么中?)。。然后在写回时,我只需遍历所有附加的标记,并将它们写入xml文件(当然还有我知道的字段)
这是众所周知的解决方案的常见问题吗
--更新日期:2012年5月22日--
我没有提到在实际的xml根节点(实际上称为注释)中,我们使用的版本号已设置为1。短期内我要做的是要求我的应用程序支持的版本号>=xml数据的版本号。如果xml是一个更大的数字,我将尝试解析以便读回,但将拒绝对模型进行任何保存。我仍然对如何实现这一点的任何工作示例感兴趣
顺便说一句,我想到了另一个很简单的解决方案。我想我可以使用XPATH查找我知道的节点,并在数据更新时替换这些节点的内容。然而,我运行了一些基准测试,当xml被解析到内存中时,解析xml的开销是荒谬的。仅仅是解析操作而不进行任何查找就导致性能比SAX差20倍。。一般来说,使用xpath进行解析的速度要慢30-50倍,考虑到我在列表视图中解析它们,这是非常糟糕的。
因此,我的想法是保持SAX将节点解析为Clip,但将整个XML存储在Clip类的一个变量中(记住,这个XML很短,小于2kb)。然后,当我要写回数据时,我可以使用XPATH替换掉我知道的原始XML中的节点
但仍然对其他解决方案感兴趣。我可能不会接受一个解决方案,除非它包含了一些代码示例。 如果你没有绑定到一个特定的XML模式,你应该考虑这样做:
<data>
<element id="title">
myTitle
</element>
<element id="date">
18/05/2012
</element>
...
</data>
我的头衔
18/05/2012
...
然后将所有这些元素存储在单个ArrayList中。
这样,您就不会丢失信息,而且您仍然可以选择要显示的元素-编辑-等等。如果您想保留尚未“使用”的节点,您可以说SAX可能不是最佳选择。您仍然可以使用某种类型的“sax存储”来保存sax事件并重放它们(有一些类似的实现),但是基于对象模型的API将更易于使用:您可以轻松地保留完整的对象模型并只更新“您的”节点
当然,你可以使用DOM,它是<强> 标准,但是你也可以考虑一些替代方案,它可以更容易地访问你将在任意数据模型中使用的特定节点。其中,JDOM()和XOM()是很有意思的候选对象。
以下是您可以使用的方法:XMLFilter
s的正确链接。下面是您的代码执行类似操作的方式:
final SAXParserFactory factory = SAXParserFactory.newInstance();
final SAXParser parser = factory.newSAXParser();
final RecorderProxy recorder = new RecorderProxy(parser.getXMLReader());
final ClipHolder clipHolder = new ClipHolder(recorder);
clipHolder.parse(new InputSource(new StringReader(srcXml)));
assertTrue(recorder.hasRecordingToReplay());
final Clip clip = clipHolder.getClip();
assertNotNull(clip);
assertEquals(clip.title, "My Title");
assertEquals(clip.category, "Blah!");
assertEquals(clip.date, Clip.DATE_FORMAT.parse("12/24/2012"));
clip.title = "My Title Updated";
clip.category = "Something else";
final ClipSerializer serializer = new ClipSerializer(recorder);
serializer.setClip(clip);
final TransformerFactory xsltFactory = TransformerFactory.newInstance();
final Transformer t = xsltFactory.newTransformer();
final StringWriter outXmlBuffer = new StringWriter();
t.transform(new SAXSource(serializer,
new InputSource()), new StreamResult(outXmlBuffer));
assertEquals(targetXml, outXmlBuffer.getBuffer().toString());
重要的方面是:
- 您的语法是围绕SAX解析器进行的
- 您的
解析器()被包裹在记录器周围片段
- 解析XML时,记录器将记录所有内容,而您的
将只查看它所知道的内容ClipHolder
- 然后你做你需要做的一切
- 然后将数据包绕在记录器上(基本上将其重新映射到自身上)
- 然后,您使用序列化程序,它将负责提供记录的事件(委托给父对象,并将
注册为self
),并覆盖它对ContentHandler
对象的说明clip
final SAXParserFactory factory = SAXParserFactory.newInstance();
final SAXParser parser = factory.newSAXParser();
final RecorderProxy recorder = new RecorderProxy(parser.getXMLReader());
final ClipHolder clipHolder = new ClipHolder(recorder);
clipHolder.parse(new InputSource(new StringReader(srcXml)));
assertTrue(recorder.hasRecordingToReplay());
final Clip clip = clipHolder.getClip();
assertNotNull(clip);
assertEquals(clip.title, "My Title");
assertEquals(clip.category, "Blah!");
assertEquals(clip.date, Clip.DATE_FORMAT.parse("12/24/2012"));
clip.title = "My Title Updated";
clip.category = "Something else";
final ClipSerializer serializer = new ClipSerializer(recorder);
serializer.setClip(clip);
final TransformerFactory xsltFactory = TransformerFactory.newInstance();
final Transformer t = xsltFactory.newTransformer();
final StringWriter outXmlBuffer = new StringWriter();
t.transform(new SAXSource(serializer,
new InputSource()), new StreamResult(outXmlBuffer));
assertEquals(targetXml, outXmlBuffer.getBuffer().toString());