DOM 处理后 XML 属性的顺序

新手上路,请多包涵

当通过标准 DOM 处理 XML 时,属性顺序在您序列化回来后无法保证。最后,这就是我在使用标准 Java XML 转换 API 序列化输出时才意识到的。

但是我确实需要保留订单。我想知道 Java 是否有可能保持通过 DOM API 处理的 XML 文件的原始属性顺序,或者以任何方式强制顺序(可能通过使用可让您设置此顺序的替代序列化 API种财产)。在我的例子中,处理减少了改变具有一堆属性的相同元素序列的某些属性(不是全部)的值,并且可能插入更多元素。

是否有任何“简单”的方法,或者我是否必须定义自己的 XSLT 转换样式表来指定输出并更改整个输入 XML 文件?

更新 我必须感谢您的所有回答。答案现在似乎比我预期的更明显。我从来没有注意过属性顺序,因为我以前从来不需要它。

要求属性顺序的主要原因是生成的 XML 文件 看起来 不同。目标是一个包含数百个警报的配置文件(每个警报都由一组属性定义)。这个文件通常随着时间的推移几乎没有修改,但保持它的顺序很方便,因为当我们需要修改某些东西时,它是手动编辑的。有时一些项目需要对该文件进行轻微修改,例如将其中一个属性设置为客户特定的代码。

我刚刚开发了一个小应用程序将原始文件(所有项目通用)与每个项目的特定部分合并(修改某些属性的值),因此项目特定文件获取基础文件的更新(新警报定义或某些属性值错误修正)。我需要有序属性的主要动机是能够通过文本比较工具(例如 Winmerge)检查应用程序的输出与原始文件的对比。如果格式(主要是属性顺序)保持不变,则很容易发现差异。

我真的认为这是可能的,因为 XML 处理程序(例如 XML Spy)允许您编辑 XML 文件并应用一些排序(网格模式)。也许我唯一的选择是使用其中一个程序来 手动 修改输出文件。

原文由 Fernando Miguélez 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 812
2 个回答

抱歉地说,但答案比“不,你不能”或“你为什么首先需要这样做?”更微妙。

简短的回答是“DOM 不允许您这样做,但 SAX 允许”。

这是因为 DOM 不关心属性顺序,因为就标准而言它毫无意义,并且在 XSL 获取输入流时,信息已经丢失。大多数 XSL 引擎实际上会优雅地保留输入流属性顺序(例如 Xalan-C(除了在一种情况下)或 Xalan-J(总是))。特别是如果你使用 <xsl:copy*>

据我所知,不保留属性顺序的情况是。 - 如果输入流是 DOM - Xalan-C:如果按字面意思插入结果树标记(例如 <elem att1={@att1} .../>

这是一个使用 SAX 的示例,供记录(也抑制 DTD 唠叨)。

 SAXParserFactory spf = SAXParserFactoryImpl.newInstance();
spf.setNamespaceAware(true);
spf.setValidating(false);
spf.setFeature("http://xml.org/sax/features/validation", false);
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
SAXParser sp = spf.newSAXParser() ;
Source src = new SAXSource ( sp.getXMLReader(), new InputSource( input.getAbsolutePath() ) ) ;
String resultFileName = input.getAbsolutePath().replaceAll(".xml$", ".cooked.xml" ) ;
Result result = new StreamResult( new File (resultFileName) ) ;
TransformerFactory tf = TransformerFactory.newInstance();
Source xsltSource = new StreamSource( new File ( COOKER_XSL ) );
xsl = tf.newTransformer( xsltSource ) ;
xsl.setParameter( "srcDocumentName", input.getName() ) ;
xsl.setParameter( "srcDocumentPath", input.getAbsolutePath() ) ;

xsl.transform(src, result );

我还想指出,出于许多反对者的意图,在 某些 情况下属性顺序 确实 很重要。

回归测试是一个明显的例子。任何被要求优化编写不太好的 XSL 的人都知道,您通常希望确保“新”结果树与“旧”结果树相似或相同。当结果树大约有 100 万行时,XML 差异工具被证明太笨重了……在这些情况下,保留属性顺序会有很大帮助。

希望这可以帮助 ;-)

原文由 Alain Pannetier 发布,翻译遵循 CC BY-SA 3.0 许可协议

查看 XML 推荐的第 3.1 节。它说,“请注意,开始标记或空元素标记中属性规范的顺序并不重要。”

如果某个软件要求 XML 元素的属性以特定顺序出现,则该软件不是在处理 XML,而是在处理表面上看起来像 XML 的文本。它需要修复。

如果它无法修复,并且您必须生成符合其要求的文件,那么您就不能可靠地使用标准 XML 工具来生成这些文件。例如,您可以尝试(按照您的建议)使用 XSLT 以定义的顺序生成属性,例如:

 <test>
   <xsl:attribute name="foo"/>
   <xsl:attribute name="bar"/>
   <xsl:attribute name="baz"/>
</test>

只是发现 XSLT 处理器发出了这个:

 <test bar="" baz="" foo=""/>

因为处理器正在使用的 DOM 按标签名称的字母顺序排列属性。 (这是 XML DOM 中常见但不普遍的行为。)

但我想强调一点。如果一个软件在某个方面违反了 XML 推荐标准,那么它很可能在其他方面也违反了它。如果以错误的顺序向其提供属性时它会中断,如果您用单引号分隔属性,或者如果属性值包含字符实体,或者 XML 推荐中提到的 XML 文档中的任何其他内容,它也可能会中断能做到这一点,这个软件的作者估计也没有想到。

原文由 Robert Rossney 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题