XSLT从多个模板匹配中写入相同的属性

时间:2016-02-23 13:15:43

标签: xml xslt xslt-2.0 dita

我有使用许多自定义属性的XML,但是当往返标准输出(在这种情况下是DITA)时,我需要将多个自定义属性中的值推送到相同的单个输出属性中。这些值可能来自与元素本身或其祖先之一匹配的模板。

这是一个简化的例子:

<concept>
    <title>Test concept</test>
    <conbody>
        <p>Info valid for everything and everyone</p>
        <p brand="product1">Some product-specific info here</p>
        <p brand="product2" country="NL">Even more specific info</p>
        <p country="NL">And this is merely localised stuff</p>
    </conbody>
</concept>

我的转换结果应该是有效的DITA,如下所示:

<concept>
    <title>Test concept</test>
    <conbody>
        <p>Info valid for everything and everyone</p>
        <p props="brand(product1)">Some product-specific info here</p>
        <p props="brand(product2) country(NL)">Even more specific info</p>
        <p props="country(NL)">And this is merely localised stuff</p>
    </conbody>
</concept>

当我尝试从各种模板匹配中写入相同的属性(每个匹配任何节点上的单个属性)时,输出中只显示一个值。我可以修改模板以使用两个通道但在某些情况下我需要三个,甚至更多,这使得它非常复杂。创建更多特定的模板,当存在一个或两个或更多属性时,需要将这些模板快速组合成一个很大的模板列表。

最简单的方法是为另一个模板创建的属性添加一个值,但我不确定是否可以在XSLT 2.0中完成 - 因为一个转换的结果不可用于另一个。我还不够专家知道是否有任何东西可以帮助我创建一个可维护的XSL。如果没有这样的选项,我想我将不得不创建一个相当复杂的多遍模板。

感谢您的肯定答案(&#34;是的,您可以这样做,这里是如何&#34;)或者是否定的答案(&#34;不,这不能在XSL 2.0和#34中完成; )。

2 个答案:

答案 0 :(得分:3)

是的,有可能,请参阅下面的可能解决方案:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="*[@brand or @country]">
        <xsl:copy>
            <xsl:variable name="props.value">
                <!-- Complete the list of profiling attributes -->
                <xsl:for-each select="@brand | @ country">
                    <xsl:value-of select="name()"/><xsl:text>(</xsl:text><xsl:value-of select="."/><xsl:text>)</xsl:text><xsl:text> </xsl:text>
                </xsl:for-each>
            </xsl:variable>
            <xsl:attribute name="props" select="normalize-space($props.value)"></xsl:attribute>
            <!-- TODO : process non-profiling attributes here... -->
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

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

在此处查看:http://xsltransform.net/bnnZWJ

旁注:我的答案与@kjhughes的不同之处在于我只选择和处理与DITA分析相关的属性 - 您不需要为id添加props或其他任何内容} attributes。

答案 1 :(得分:2)

调整心智模型,使其远离从多个模板写入单个属性值。相反,请考虑您希望属性值是什么以及如何从XSLT中的单个位置 中输入XML 的部分收集属性值的各个部分

您的大部分输出应与输入相同,因此请从身份转换开始。然后为p编写一个特殊案例模板,您可以通过迭代输入@props元素的属性来创建其特殊的p属性。

以下是基础知识......

根据您的XML输入,

<concept>
    <title>Test concept</title>
    <conbody>
        <p>Info valid for everything and everyone</p>
        <p brand="product1">Some product-specific info here</p>
        <p brand="product2" country="NL">Even more specific info</p>
        <p country="NL">And this is merely localised stuff</p>
    </conbody>
</concept>

此XSLT 1.0(或2.0)转换,

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

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

  <xsl:template match="p[@*]">
    <xsl:copy>
      <xsl:attribute name="props">
        <xsl:for-each select="@*">
          <xsl:value-of select="name()"/>
          <xsl:text>(</xsl:text>
          <xsl:value-of select="."/>
          <xsl:text>)</xsl:text>
          <xsl:if test="position() != last()">
            <xsl:text> </xsl:text>
          </xsl:if>
        </xsl:for-each>
      </xsl:attribute>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

将产生此XML输出

<?xml version="1.0" encoding="UTF-8"?>
<concept>
    <title>Test concept</title>
    <conbody>
        <p>Info valid for everything and everyone</p>
        <p props="brand(product1)">Some product-specific info here</p>
        <p props="brand(product2) country(NL)">Even more specific info</p>
        <p props="country(NL)">And this is merely localised stuff</p>
    </conbody>
</concept>
根据要求