背景
第三方軟體庫有時包括一組開發人員在使用該庫時可以選擇的許可證。可以使用ORT檢測某些許可證以生成SPDX 識別符號。我們希望消除每次選擇特定許可證的手動程序,而是遵循預定義的優先串列。
并非所有許可證都包含在串列中。
代碼
本節定義源檔案。
優先級.xml
條目的順序決定了選擇可用時選擇的許可證:
<priorities>
<license>Apache-2.0</license>
<license>MIT</license>
<license>BSD-2-Clause</license>
<license>BSD-3-Clause</license>
<license>CDDL-1.0</license>
<license>EPL-2.0</license>
<license>MPL-2.0</license>
<license>LGPL-3.0</license>
</priorities>
該檔案使用以下方式加載:
<xsl:variable
name="PRIORITY"
select="document( resolve-uri( 'priorities.xml', base-uri( / ) ) )" />
庫.xml
這些簡化的許可證條目構成輸入檔案:
<copyrights>
<copyright>
<title>Grizzly HTTP framework</title>
<licenses>
<license>CDDL-1.0</license>
<license>GPL-2.0-or-later</license>
</licenses>
</copyright>
<copyright>
<title>Java? JSON Tools Jackson Coreutils</title>
<licenses>
<license>LGPL-3.0-or-later</license>
<license>Apache-2.0</license>
</licenses>
</copyright>
<copyright>
<title>Javassist</title>
<licenses>
<license>LGPL-2.1-only</license>
<license>MPL-1.1</license>
<license>Apache-2.0</license>
</licenses>
</copyright>
<copyright>
<title>Linux Kernel</title>
<licenses>
<license with="Linux-syscall-note" order="before">GPL-2.0-only</license>
</licenses>
</copyright>
<copyright>
<title>Eclipse Temurin?</title>
<licenses>
<license with="Classpath-exception-2.0">GPL-2.0-only</license>
</licenses>
</copyright>
</copyrights>
輸出
所需的輸出將許可證減少到一個條目:
<copyrights>
<copyright>
<title>Grizzly HTTP framework</title>
<licenses>
<license>CDDL-1.0</license>
</licenses>
</copyright>
<copyright>
<title>Java? JSON Tools Jackson Coreutils</title>
<licenses>
<license>Apache-2.0</license>
</licenses>
</copyright>
<copyright>
<title>Javassist</title>
<licenses>
<license>Apache-2.0</license>
</licenses>
</copyright>
<copyright>
<title>Linux Kernel</title>
<licenses>
<license with="Linux-syscall-note" order="before">GPL-2.0-only</license>
</licenses>
</copyright>
<copyright>
<title>Eclipse Temurin?</title>
<licenses>
<license with="Classpath-exception-2.0">GPL-2.0-only</license>
</licenses>
</copyright>
</copyrights>
問題
從概念上講,我想根據每個輸入許可證在優先級串列中的位置過濾掉許可證,然后選擇第一個。作為一系列轉換,輸入檔案的相關部分可能開始于:
<licenses>
<license>LGPL-2.1-only</license>
<license>MPL-1.1</license>
<license>Apache-2.0</license>
</licenses>
然后我們可以根據優先級串列中的位置分配優先級:
<licenses>
<license priority="INFINITY">LGPL-2.1-only</license>
<license priority="7">MPL-1.1</license>
<license priority="1">Apache-2.0</license>
</licenses>
然后根據優先級排序:
<licenses>
<license priority="1">Apache-2.0</license>
<license priority="7">MPL-1.1</license>
<license priority="INFINITY">LGPL-2.1-only</license>
</licenses>
然后選擇第一個孩子:
<licenses>
<license priority="1">Apache-2.0</license>
</licenses>
我相信這種“演算法”將確保默認選擇任何沒有相應優先級的許可證。
約束
這些約束將在轉換步驟發生之前得到滿足:
如果輸入檔案中存在多個許可證,但許可證優先級串列中沒有至少一個匹配項,則這是錯誤的。在這種情況下,我認為我們不能現實地選擇第一個許可證。
輸入檔案中的每個條目都沒有許可證是錯誤的(即,我們可以使用模式驗證來強制執行此操作)。
問題
使用 XSLT 3.0 過濾許可證的便捷方法是什么?
uj5u.com熱心網友回復:
嘗試:
<xsl:template match="copyright/licenses">
<licenses>
<xsl:copy-of
select="$PRIORITY//license[. = current()/license][1]"/>
</licenses>
</xsl:template>
這利用了使用 進行一對多比較的能力=。
并非源檔案中的所有許可證都列在優先級檔案中,因此要包含默認值并保留源檔案中的屬性,請嘗試:
<xsl:template match="copyright/licenses">
<licenses>
<xsl:copy-of
select="(license[.=$PRIORITY//license[. = current()/license][1]], license)[1]" />
</licenses>
</xsl:template>
uj5u.com熱心網友回復:
這是我的建議。
為了簡化我的測驗,我定義了PRIORITY變數 inline 而不是使用document(),但當然你可以堅持從外部檔案讀取它的方法。
一個解釋:
模板匹配licenses只復制其中一個license子元素。
首先,它使用 XPath 3sort功能對許可證進行排序。該函式的最后一個引數是將專案映射到排序鍵的函式;提供的函式在許可證序列中查找專案(即許可證名稱)PRIORITY,并回傳結果位置,或者如果在地圖中未找到,則回傳無窮大。
然后復制該排序序列中的第一個(最高優先級)許可證。
<xsl:stylesheet
version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
<xsl:variable name="PRIORITY">
<priorities>
<license>Apache-2.0</license>
<license>MIT</license>
<license>BSD-2-Clause</license>
<license>BSD-3-Clause</license>
<license>CDDL-1.0</license>
<license>EPL-2.0</license>
<license>MPL-2.0</license>
<license>LGPL-3.0</license>
</priorities>
</xsl:variable>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="licenses" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:copy>
<xsl:copy-of select="
sort(
license,
(),
function($license) {
(index-of($PRIORITY//license, $license), xs:double('INF'))[1]
}
)[1]
"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
uj5u.com熱心網友回復:
這是 Michael Kay 使用鍵的建議的實作——我相信這會更有效。
為了更好的可讀性,我使用了變數。如果您更喜歡簡潔的代碼,可以將每個變數參考替換為其select運算式。
<xsl:key name="lic" match="license" use="." />
<xsl:template match="licenses">
<xsl:copy>
<xsl:variable name="related" select="key('lic', license, $PRIORITY)" />
<xsl:variable name="top" select="key('lic', $related[1], current())" />
<xsl:copy-of select="($top, license)[1]" />
</xsl:copy>
</xsl:template>
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/512785.html
