【发布时间】:2021-12-26 05:50:42
【问题描述】:
我正在对由第三方应用程序生成的一堆 XML 文件进行版本控制。不幸的是,这些文件的保存方式通常使版本控制比应有的更加麻烦。他们可能会交换元素:
<root>
- <b>bar</b>
<a>foo</a>
+ <b>bar</b>
</root>
或重新排序属性:
-<root a="foo" b="bar"/>
+<root b="bar" a="foo"/>
或更改/删除缩进:
-<root a="foo" b="bar"/>
+<root
+ a="foo"
+ b="bar"/>
需要明确的是,这些文件不会混合文本和元素节点(如 <a>foo <b>bar</b></a>),并且不同排序的文件之间没有语义差异,因此可以按照我们想要的方式重新排序它们是安全的。
我通过使用xsltproc 和以下schema 对元素进行排序,部分解决了这个问题:
<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform">
<output method="xml" indent="yes" encoding="UTF-8"/>
<strip-space elements="*"/>
<template match="processing-instruction()|@*">
<copy>
<apply-templates select="node()|@*"/>
</copy>
</template>
<template match="*">
<copy>
<apply-templates select="@*"/>
<apply-templates>
<sort select="name()"/>
<sort select="@*[1]"/>
<sort select="@*[2]"/>
<sort select="@*[3]"/>
<sort select="@*[4]"/>
<sort select="@*[5]"/>
<sort select="@*[6]"/>
</apply-templates>
</copy>
</template>
</stylesheet>
但是,我最近了解到attribute ordering is not defined,因此按六个“第一”属性排序通常不起作用。当然,这不会对属性进行排序。
(我在标题中使用了“normalize”,因为我不一定想以某种特定方式对元素进行排序,这似乎是确保文本文本的最明显方式两个语义相同的文件之间的区别是空的。)
有没有办法实现这样的排序?
尽管有名字,但这与XSLT sort by tag name and attribute value 不同。该问题仅包含一个属性,并且公认的解决方案不够通用。
【问题讨论】:
-
您可以尝试简单地将数据转换为规范 XML - 尽管规范 XML 假定元素顺序很重要。