避免在XSLT中使用循环键定义

时间:2018-10-08 16:36:05

标签: xslt-3.0

我正在编写一些代码,这些代码将有效的XML实例转换为DITA代码块中的代码表示形式。

我的输入中包含一些包装元素,使我可以对输出定义一些重点。对于node()项,这很容易,因为包装器直接包装了要强调的代码。但是,对于属性等,我需要在强调元素上指定一些@select。

以下是我尝试执行此操作的简短代码摘录(针对属性;对于其他类型的内容,我已删除了类似的模板):

<xsl:key name="emph" match="eg:emph[@select]">
    <xsl:variable name="selected">
        <xsl:evaluate xpath="@select" context-item="."/>
    </xsl:variable>
    <xsl:for-each select="$selected">
        <xsl:sequence select="generate-id()"/>
    </xsl:for-each>
</xsl:key>


<xsl:template match="@*[key('emph', generate-id(.))]" mode="eg">
    <xsl:variable name="style" select="if (not(key('emph', generate-id(.))/@style)) then 'italic' else key('emph', generate-id())/@style"/>
    <xsl:text> </xsl:text>
    <ph outputclass="{$style}">
        <xsl:next-match>
            <xsl:with-param name="includeSpace" select="false()"/>
        </xsl:next-match>
    </ph>
</xsl:template>

<xsl:template match="@*" mode="eg">
    <xsl:param name="includeSpace" as="xs:boolean" select="true()"/>
    <xsl:if test="$includeSpace">
        <xsl:text> </xsl:text>
    </xsl:if>
    <ph outputclass="AttributeName">
        <xsl:value-of select="name()"/>
    </ph>
    <ph outputclass="equals">=</ph>
    <ph outputclass="attributeQuotes">&quot;</ph>
    <ph outputclass="AttributeValue">
        <xsl:value-of select="."/>
    </ph>
    <ph outputclass="attributeQuotes">&quot;</ph>
</xsl:template>

输入诸如:

<eg:emph select="abbrev-journal-title/@abbrev-type">
    <abbrev-journal-title abbrev-type="custom">JPhysA</abbrev-journal-title>
</eg:emph>

我想生成类似这样的东西:

<ph outputclass="XmlFurniture">&lt;</ph><ph outputclass="ElementName">abbrev-journal-title</ph> <ph outputclass="italic"><ph outputclass="AttributeName">abbrev-type</ph><ph outputclass="equals">=</ph><ph outputclass="attributeQuotes">"</ph><ph outputclass="AttributeValue">custom</ph><ph outputclass="attributeQuotes">"</ph></ph><ph outputclass="XmlFurniture">&gt;</ph>JPhysA<ph outputclass="XmlFurniture">&lt;/</ph><ph outputclass="ElementName">abbrev-journal-title</ph><ph outputclass="XmlFurniture">&gt;</ph>

使用Saxon(PE 9.8.0.12)进行转换会返回“键定义是循环的”错误-但据我所知,实际上并非如此。

任何人都可以提出解决方法,或者至少解释为什么这种方法行不通吗?

1 个答案:

答案 0 :(得分:2)

关于// JSON Struct struct Item : Codable { var name : String var price : String init(name: String, price: String) { self.name = name self.price = price } } // Array Declarations var billing_array = [Item]() // JSON Parsing if let results = result["result"] as? [String: AnyObject] { self.billing_array.append(results) } // TableView Delegation func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.billing_array.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell let item = billing_array[indexPath.row] cell.product_name.text = item.name cell.product_price.text = item.price return cell } 的使用,请参见https://www.w3.org/TR/xslt-30/#evaluate-dynamic-context解释

  

上下文项,位置和大小取决于结果   计算xsl:evaluate属性中的表达式。如果这   属性不存在,或者如果结果为空序列,则   用于评估目标的上下文项,位置和大小   表情都没有。

由于您在尝试使用context-item时都没有在context-item上设置属性xsl:evaluate毫无意义,所以我想您想使用xpath="@select"选择匹配的元素。

关于选择属性节点并将其存储在变量中,我认为您需要使用

context-item="."

代替

<xsl:variable name="selected" as="attribute()*">
    <xsl:evaluate xpath="@select" context-item="."/>
</xsl:variable>

那我会认为

<xsl:variable name="selected">
    <xsl:evaluate xpath="@select" context-item="."/>
</xsl:variable>

可以缩短/简化为

<xsl:for-each select="$selected">
    <xsl:sequence select="generate-id()"/>
</xsl:for-each>

在XSLT 3中。

我现在尝试构建一个最小但完整的示例,并使用Saxon 9.8.0.12 EE和Saxon 9.9.0.1 EE来使用Saxon进行测试,我没有发现任何错误,并且该方法对于您所使用的模板似乎有效已创建。

测试XSLT是:

<xsl:sequence select="$selected!generate-id()"/>

样本输入为

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:eg="http://example.com/eg"
    exclude-result-prefixes="#all"
    default-mode="eg"
    version="3.0">

    <xsl:mode name="eg" on-no-match="shallow-copy"/>

    <xsl:output indent="yes"/>

    <xsl:key name="emph" match="eg:emph[@select]">
        <xsl:variable name="selected" as="attribute()*">
            <xsl:evaluate xpath="@select" context-item="."/>
        </xsl:variable>
        <xsl:sequence select="$selected ! generate-id()"/>
    </xsl:key>


    <xsl:template match="@*[key('emph', generate-id(.))]" mode="eg">
        <xsl:variable name="style" select="if (not(key('emph', generate-id(.))/@style)) then 'italic' else key('emph', generate-id())/@style"/>
        <xsl:text> </xsl:text>
        <ph outputclass="{$style}">
            <xsl:next-match>
                <xsl:with-param name="includeSpace" select="false()"/>
            </xsl:next-match>
        </ph>
    </xsl:template>

    <xsl:template match="@*" mode="eg">
        <xsl:param name="includeSpace" as="xs:boolean" select="true()"/>
        <xsl:if test="$includeSpace">
            <xsl:text> </xsl:text>
        </xsl:if>
        <ph outputclass="AttributeName">
            <xsl:value-of select="name()"/>
        </ph>
        <ph outputclass="equals">=</ph>
        <ph outputclass="attributeQuotes">&quot;</ph>
        <ph outputclass="AttributeValue">
            <xsl:value-of select="."/>
        </ph>
        <ph outputclass="attributeQuotes">&quot;</ph>
    </xsl:template>

</xsl:stylesheet>

结果显示属性已匹配并转换:

<root>
    <eg:emph select="abbrev-journal-title/@abbrev-type" xmlns:eg="http://example.com/eg">
        <abbrev-journal-title abbrev-type="custom">JPhysA</abbrev-journal-title>
    </eg:emph>  
    <eg:emph select="abbrev-journal-title/@abbrev-type" xmlns:eg="http://example.com/eg" style="bold">
        <abbrev-journal-title abbrev-type="custom">JPhysA</abbrev-journal-title>
    </eg:emph>  
</root>