XML 命名空間支援

Apache Ant 1.6 引進了對 XML 命名空間的支援。

歷史

Ant 1.6 之前的 Ant 所有版本都不支援 XML 命名空間。在此,不支援基本上表示兩件事

過去不鼓勵在元素名稱中使用冒號,而 XML 規格強烈建議不要使用任何以 xml 開頭的屬性,以保留此類名稱供未來使用。

動機

在建置檔案中使用大量自訂和第三方任務時,很容易產生名稱衝突。當定義個別類型時,建置檔案撰寫者可以手動執行一些命名空間處理(例如,使用 tomcat-deploy 而不是僅使用 deploy)。但當使用 <typedef> resource 屬性定義整個類型函式庫時,建置檔案撰寫者無法覆寫或甚至為函式庫提供的名稱加上前置詞。

指定命名空間

<typedef> 新增 prefix 屬性可能就夠了,但 XML 已經有廣為人知的命名空間方法。因此,<typedef><taskdef> 任務會取得 uri 屬性,而不是新增 prefix 屬性,該屬性會儲存類型應該與之關聯的 XML 命名空間的 URI

<typedef resource="org/example/tasks.properties" uri="http://example.org/tasks"/>
<my:task xmlns:my="http://example.org/tasks">
    ...
</my:task>

如同上述範例所示,命名空間 URI 需要至少指定兩次:一次作為 uri 屬性的值,另一次則透過使用 xmlns 屬性將命名空間實際對應至來自該命名空間的元素出現。此對應可以在建置檔案中的任何層級發生

<project name="test" xmlns:my="http://example.org/tasks">
    <typedef resource="org/example/tasks.properties" uri="http://example.org/tasks"/>
    <my:task>
        ...
    </my:task>
</project>

當然,使用命名空間前置詞是選用的。因此,範例也可以像這樣

<project name="test">
    <typedef resource="org/example/tasks.properties" uri="http://example.org/tasks"/>
    <task xmlns="http://example.org/tasks">
        ...
    </task>
</project>

在此,命名空間設定為 <task> 元素及其所有後代的預設命名空間。

預設命名空間

Ant 使用的預設命名空間為 antlib:org.apache.tools.ant

<typedef resource="org/example/tasks.properties" uri="antlib:org.apache.tools.ant"/>
<task>
    ...
</task>

命名空間和巢狀元素

在 Ant 1.6 中,巢狀在命名空間元素內的元素幾乎總是與其父元素具有相同的命名空間。因此,如果上方範例中的 task 允許巢狀 config 元素,則建置檔案片段會如下所示

<typedef resource="org/example/tasks.properties" uri="http://example.org/tasks"/>
<my:task xmlns:my="http://example.org/tasks">
    <my:config a="foo" b="bar"/>
    ...
</my:task>

如果元素允許或需要許多巢狀元素,則必須對每個巢狀元素使用前綴。將命名空間設為預設值可以減少指令碼的冗長性

<typedef resource="org/example/tasks.properties" uri="http://example.org/tasks"/>
<task xmlns="http://example.org/tasks">
    <config a="foo" b="bar"/>
    ...
</task>

自 Ant 1.6.2 起,巢狀在命名空間元素內的元素也可以位於 Ant 的預設命名空間中。這表示現在允許使用下列內容

<typedef resource="org/example/tasks.properties"
    uri="http://example.org/tasks"/>
<my:task xmlns:my="http://example.org/tasks">
    <config a="foo" b="bar"/>
    ...
</my:task>

命名空間和屬性

僅在下列情況下,屬性才會用於設定它們所屬的元素

自 Ant 1.9.1 起,可以使用兩個屬性命名空間 ant:ifant:unless,讓您有條件地插入元素。

其他屬性只會被忽略。

這表示

<my:task xmlns:my="http://example.org/tasks">
    <my:config a="foo" b="bar"/>
    ...
</my:task>

<my:task xmlns:my="http://example.org/tasks">
    <my:config my:a="foo" my:b="bar"/>
    ...
</my:task>

都會導致參數 ab 被用作參數來設定巢狀 config 元素。

這也表示您可以使用其他命名空間的屬性,以額外的元資料標記建置檔案,例如 RDF 和 XML-Schema(無論這是否是一件好事)。對於來自未知命名空間的元素,情況並非如此,這會導致錯誤。

混合來自不同命名空間的元素

現在進入困難的部分:在某些情況下,可以將來自不同命名空間的元素交織在一起。這與 Ant 1.6 新增類型內省規則有很大關係:只要具體類型實作任務/類型所預期的介面,Ant 類型和任務現在就可以自由地接受任意命名類型作為巢狀元素。最明顯的範例是 <condition> 任務,它支援各種巢狀條件,而所有這些條件都延伸了介面 Condition。若要將自訂條件整合到 Ant 中,您現在可以簡單地 <typedef> 條件,然後在允許巢狀條件的任何地方使用它(假設包含元素具有通用 add(Condition)addConfigured(Condition) 方法)

<typedef resource="org/example/conditions.properties" uri="http://example.org/conditions"/>
<condition property="prop" xmlns="http://example.org/conditions">
    <and>
        <available file="bla.txt"/>
        <my:condition a="foo"/>
    </and>
</condition>

在 Ant 1.6 中,我們無法像預期的那樣大量使用這項功能:許多程式碼尚未適應新的內省規則,而 Ant 的內建條件和選擇器等元素在 1.6 中並非真正的類型。預計這會在 Ant 1.7 中有所改變。

命名空間和 Antlib

新的 AntLib 功能也與 Ant 1.6 中的命名空間支援密切整合。基本上,您可以透過使用命名空間 URI 的特殊配置來「匯入」Antlib:antlib 配置,它預期套件名稱位於其中一個特殊的 antlib.xml 檔案。