2010-10-27 50 views
3

根据一些参数,我需要在安装后更改XML文件。带内联XSLT的XML

例如:

<?xml ...?> 
<root xmlns="..."> 

    <!-- remove this element when PARAM_MODE=1 --> 
    <sometag /> 

    <!-- remove this element when PARAM_MODE=2 --> 
    <sometag2 /> 

    <someothertag /> 
</root> 

它使用XSLT要删除的元素,但我想评论和XSL进行组合和不可复制的最简单方法。

有什么可以做到的吗?事情是这样的:

<?xml ...?> 
<root xmlns="..." xmlns:xsl="XSL_NAMESPACE"> 
    <!-- XSL to remove this element when PARAM_MODE=1 --> 
    <xsl:remove the attribute if $PARAM_MODE=1 /> 
    <sometag /> 

    <!-- XSL to remove this element when PARAM_MODE=2 --> 
    <xsl:remove the attribute if $PARAM_MODE=2 /> 
    <sometag2 /> 

    <someothertag /> 
</root> 

回答

3

这个样式表:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:my="..."> 
    <xsl:param name="PARAM_MODE" select="1"/> 
    <xsl:template match="@*|node()" name="identity"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="my:sometag"> 
     <xsl:if test="$PARAM_MODE!=1"> 
      <xsl:call-template name="identity"/> 
     </xsl:if> 
    </xsl:template> 
    <xsl:template match="my:sometag2"> 
     <xsl:if test="$PARAM_MODE!=2"> 
      <xsl:call-template name="identity"/> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

有了这个输入:

<root xmlns="..."> 
    <!-- remove this element when PARAM_MODE=1 --> 
    <sometag /> 
    <!-- remove this element when PARAM_MODE=2 --> 
    <sometag2 /> 
    <someothertag /> 
</root> 

输出:

<root xmlns="..."> 
    <!-- remove this element when PARAM_MODE=1 --> 
    <!-- remove this element when PARAM_MODE=2 --> 
    <sometag2></sometag2> 
    <someothertag></someothertag> 
</root> 

请注意,如果你想有一个简化信达X,从http://www.w3.org/TR/xslt#result-element-stylesheet

的简化语法允许 样式表仅由根节点一个 单个模板的。 样式表可能只包含一个 文字结果元素(请参阅7.1.1 Literal Result Elements)。这样的 样式表相当于 样式表,其中xsl:样式表 元素包含包含文字结果元素的模板规则 ; 模板规则具有/的匹配模式 。

因此,您可以添加元素,但不能剥离它们。

编辑:用于简化语法的反转逻辑。

假设这个样式表与... test.xsl URI:

<?xml-stylesheet type="text/xsl" href="test.xsl"?> 
<root 
xmlns="..." 
xmlns:my="..." 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xsl:version="1.0"> 
    <PARAM_MODE>1</PARAM_MODE> 
    <!-- remove this element when PARAM_MODE=1 --> 
    <xsl:if test="document('')/my:root/my:PARAM_MODE!=1"> 
     <sometag /> 
    </xsl:if> 
    <!-- remove this element when PARAM_MODE=2 --> 
    <xsl:if test="document('')/my:root/my:PARAM_MODE!=2"> 
     <sometag2 /> 
    </xsl:if> 
    <someothertag /> 
</root> 

运行过程中出现以自己为输入(我用PI强调这也,这使得fn:document()多余的......),输出:

<root xmlns="..." xmlns:my="..."> 
    <PARAM_MODE>1</PARAM_MODE> 
    <sometag2 /> 
    <someothertag /> 
</root> 

最后的意见驱动的样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:param name="PARAM_MODE" select="1"/> 
    <xsl:template match="@*|node()" name="identity"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="*[preceding-sibling::node()[1] 
          /self::comment()[starts-with(.,' remove ')]]"> 
     <xsl:if test="$PARAM_MODE != substring-after(
             preceding-sibling::comment()[1], 
             'PARAM_MODE=')"> 
      <xsl:call-template name="identity"/> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

输出:

<root xmlns="..."> 
    <!-- remove this element when PARAM_MODE=1 --> 
    <!-- remove this element when PARAM_MODE=2 --> 
    <sometag2></sometag2> 
    <someothertag></someothertag> 
</root> 
+1

1为工作答案和探索使用的隐含可能性简化的语法。我认为你表明他的要求“我希望将评论和XSL结合起来而不是重复”可能是不可能的。 – LarsH 2010-10-27 14:58:48

+0

P.S.我在想,@Vitaly想根据评论的存在来剥离元素,而不是基于元素名称。但这并不完全清楚。 – LarsH 2010-10-27 15:04:32

+1

@LarsH:我同意它不清楚。 'PARAM_MODE'也可以是一个元素。关于简化的语法:我不认为这是不可能的,因为你总是可以颠倒逻辑:'< - 删除该元素时PARAM_MODE = 1 - >的< - 删除该元素时PARAM_MODE = 2 - >的' – 2010-10-27 15:30:09

1

这个样式表使用commentparam值来确定纂哪些内容。

灵感来自XPATH找到合适的元素是从@Dimitre Novatchev's answer for xslt and xpath: match preceding comments派生。

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

    <xsl:param name="PARAM_MODE" /> 

    <!--Match on the comments to remove elements, and the elements immediately following --> 

    <xsl:template match="comment()[starts-with(.,' remove this element when PARAM_MODE=')] 
     | 
     *[self::*[ 
       generate-id(
        preceding-sibling::comment() 
         [1] 
         [starts-with(.,' remove this element when PARAM_MODE=')] 
        /following-sibling::node() 
         [1] 
         [self::text() and not(normalize-space())] 
        /following-sibling::node() 
         [1] 
         [self::*] 
       )=generate-id() 
      ] 
     ]"> 

     <!--Param/Variable references are not allowed in the match expression, so we will need to do a little work inside of the template --> 
     <xsl:choose> 
      <!--If the PARAM_MODE value matches the comment, or it's the element immediately following, then remove it --> 
      <xsl:when test="(self::comment() and substring-after(.,'=')=$PARAM_MODE) 
       or 
       (self::*[ 
         generate-id(
          preceding-sibling::comment() 
           [1] 
           [starts-with(.,' remove this element when PARAM_MODE=') 
            and substring-after(.,'=')=$PARAM_MODE] 
          /following-sibling::node() 
           [1] 
           [self::text() and not(normalize-space())] 
          /following-sibling::node() 
           [1] 
           [self::*] 
         )=generate-id() 
        ])" /> 
      <xsl:otherwise> 
       <!--Otherwise, invoke the identity template and copy forward --> 
       <xsl:call-template name="identity"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

<!--Identity template that copies content into the result document --> 
    <xsl:template match="@*|node()" name="identity"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

当应用于此XML文档(有参数PARAM_MODE = 2):

<?xml version="1.0" encoding="UTF-8"?> 
<root xmlns="..."> 

    <!-- remove this element when PARAM_MODE=1 --> 
    <sometag /> 

    <!-- remove this element when PARAM_MODE=2 --> 
    <sometag2 /> 

    <someothertag /> 
</root> 

以下输出产生:

<?xml version="1.0" encoding="UTF-8"?> 
<root xmlns="..."> 

    <!-- remove this element when PARAM_MODE=1 --> 
    <sometag/> 




    <someothertag/> 
</root> 
1

下面是一个方法,它允许内容的评论驱动器是否将评论后面的元素复制到输出中。详细信息请参阅转换中的注释。

使用此输入:

<?xml version="1.0" encoding="utf-8" ?> 
<tle> 
    <!-- remove this element if $param = 1--> 
    <foo/> 
    <dont_remove/> 
    <dont_remove/> 
    <!-- remove this element if $param = 2--> 
    <bar/> 
    <dont_remove/> 
    <dont_remove/> 
    <dont_remove/> 
</tle> 

和此变换:

<?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:variable name="param">2</xsl:variable> 

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

    <!-- this matches only elements whose immediately preceding non-text node is 
     a comment; all other elements are copied to the output by the identity 
     template. 

     it ignores text nodes so that whitespace between the comment and the 
     element it's tagging doesn't break their association. 
    --> 
    <xsl:template match="match="*[preceding-sibling::node() 
           [not(self::text())] 
           [1] 
           [self::comment()] 
           ]"> 
    <!-- find the immediately preceding comment --> 
    <xsl:variable name="comment" select="preceding-sibling::comment()[1]"/> 
    <!-- don't copy this element if the text of the comment matches the 
     value of $param --> 
    <xsl:choose> 
     <xsl:when test="$param = 1 and contains($comment, 'param = 1')"/> 
     <xsl:when test="$param = 2 and contains($comment, 'param = 2')"/> 
     <xsl:otherwise> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()"/> 
     </xsl:copy> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 

</xsl:stylesheet> 

产生这样的输出:

<tle> 
    <!-- remove this element if $param = 1--> 
    <foo /> 
    <dont_remove /> 
    <dont_remove /> 
    <!-- remove this element if $param = 2--> 

    <dont_remove /> 
    <dont_remove /> 
    <dont_remove /> 
</tle>