如何规范 XML 元素和属性的顺序?

Posted

技术标签:

【中文标题】如何规范 XML 元素和属性的顺序?【英文标题】:How to normalize the sequence of XML elements and attributes? 【发布时间】: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"/>

需要明确的是,这些文件不会混合文本和元素节点(如 &lt;a&gt;foo &lt;b&gt;bar&lt;/b&gt;&lt;/a&gt;),并且不同排序的文件之间没有语义差异,因此可以按照我们想要的方式重新排序它们是安全的。

我通过使用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 假定元素顺序很重要。 【参考方案1】:

这个练习的目的并不完全清楚。如果您只想“规范化”(规范化?)不同的文档,以便元素及其属性以相同的顺序(和缩进)出现,您可以简单地做:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*">
            <xsl:sort select="name()"/>
        </xsl:apply-templates>
        <xsl:apply-templates select="node()">
            <xsl:sort select="name()"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

当它应用于以下输入时:

XML 1

<input shape="circle" size="large" color="blue">
    <shape>circle</shape>
    <size>large</size>
    <color>blue</color>
</input>

XML 2

<input color="red" size="small" shape="square">
    <color>red</color>
    <size>small</size>
    <shape>square</shape>
</input>

结果将分别为:

结果 1

<?xml version="1.0" encoding="UTF-8"?>
<input color="blue" shape="circle" size="large">
  <color>blue</color>
  <shape>circle</shape>
  <size>large</size>
</input>

结果 2

<?xml version="1.0" encoding="UTF-8"?>
<input color="red" shape="square" size="small">
  <color>red</color>
  <shape>square</shape>
  <size>small</size>
</input>

注意: 由于the order of attributes is by definition insignificant,XSLT 处理器没有义务按照指令对它们进行排序。但是,实际上大多数处理器都会这样做。

【讨论】:

以上是关于如何规范 XML 元素和属性的顺序?的主要内容,如果未能解决你的问题,请参考以下文章

XML_03_XML文档类型定义DTD

Xml Jaxb 命名空间和属性顺序

什么可以改变Java生成的XML文件中元素属性的顺序?

如何在反向域名排序和自定义筛选上规范化XML

Caused by: org.xml.sax.SAXParseException: 元素类型 “insert“ 必须后跟属性规范 “>“ 或 “/>“。

如何检查未知的 XML 文件以获取其元素或属性?