DOM处理后的XML属性顺序

Fer*_*lez 42 java xml dom

通过标准DOM处理XML时,序列化后不保证属性顺序.最后,这就是我在使用标准java XML Transform API序列化输出时所实现的.

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

有没有"简单"的方法,还是我必须定义自己的XSLT转换样式表来指定输出并更改整个输入XML文件?

更新我必须感谢你的所有答案.答案似乎比我预期的更明显.我从未关注属性顺序,因为我之前从未需要它.

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

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

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

Rob*_*ney 25

请参阅XML建议的第3.1节.它说,"请注意,start-tag或empty-element标签中属性规范的顺序并不重要."

如果一个软件要求XML元素上的属性以特定顺序出现,该软件不处理XML,那么它处理的文本看起来就像XML一样.它需要修复.

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

<test>
   <xsl:attribute name="foo"/>
   <xsl:attribute name="bar"/>
   <xsl:attribute name="baz"/>
</test>
Run Code Online (Sandbox Code Playgroud)

只是发现XSLT处理器发出这样的:

<test bar="" baz="" foo=""/>
Run Code Online (Sandbox Code Playgroud)

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

但我想强调一些事情.如果某个软件在某个方面违反了XML建议,则可能在其他方面违反了该建议.如果在以错误的顺序提供属性时它会中断,如果使用单引号分隔属性,或者属性值包含字符实体,或者XML建议说XML文档中的任何其他内容,它可能也会中断可以做到这个软件的作者可能没有想到.


小智 25

很抱歉,但答案比"不能你不能"或"你为什么首先需要这样做?"更为微妙.

简短的回答是"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 );
Run Code Online (Sandbox Code Playgroud)

我还想指出的是,在许多反对者的意图存在情况下,属性顺序的事情.

回归测试是一个明显的例子.任何被称为优化编写不太好的XSL的人都知道你通常希望确保"新"结果树与"旧"结果树相似或相同.当结果树大约有一百万行时,XML diff工具证明过于笨拙......在这些情况下,保留属性顺序非常有帮助.

希望这可以帮助 ;-)

  • 版本控制中的干净差异是保持文件顺序相同的另一个原因. (12认同)
  • @JohnSaunders另一方面,关于XML的一个美妙之处在于人类可以阅读它,至少在LtoR国家,我们倾向于寻找对L的重要事物,对R来说重要性较低.所以,理想情况下在创建XML时保留顺序会很好,因为创建者可能已经认为属性排序对人类很重要.至少,这应该是编写器或文档对象的选项. (7认同)
  • 请允许我对旧答案添加评论。很可能某些 SAX 解析器保留了属性顺序,或者他们在 2010 年就这样做了。但这不是规范的一部分,并且依赖于特定实现的意外未指定属性并不是好的工程。 (2认同)

Jon*_*nna 9

XML Canonicalisation导致一致的属性排序,主要是为了允许人们检查一些或所有XML的签名,尽管还有其他潜在的用途.这可能适合您的目的.


Joh*_*ers 8

不可能过分强调罗伯特罗斯尼刚刚说的话,但我会试试.;-)

国际标准的好处是,当每个人都遵循它们时,生活是美好的.我们所有的软件都和平相处.

XML必须是我们最重要的标准之一.它是像SOAP这样的"旧网"东西的基础,还有像RSS和Atom这样的"web 2.0".这是因为XML能够在不同平台之间进行互操作的明确标准.

如果我们一点一点地放弃XML,我们将陷入这样一种情况,即XML的生产者将无法假设XML的使用者能够使用他们的内容.这将对该行业产生灾难性影响.

对于根据标准编写不处理XML的代码的任何人,我们应该非常有力地推迟.我理解,在这些经济时代,人们不愿意冒犯"不"来冒犯客户和商业伙伴.但在这种情况下,我认为这是值得的.如果我们不得不为每个业务合作伙伴手工制作XML,那么我们的财务状况会更差.

因此,不要"启用"不了解XML的公司.向他们发送标准,突出显示相应的行.他们需要不再认为XML只是带有尖括号的文本.它的行为与表示尖括号的文本不同.

这不是有借口的.即使最小的嵌入式设备也可以在其中使用全功能的XML解析器实现.我还没有听到过无法解析标准XML的充分理由,即使人们无法负担全功能的DOM实现.