为什么即使xpath正确,我的xslt仍在输出中显示错误的值?

时间:2018-10-06 00:14:28

标签: xml xslt

这是我的XML代码的相关部分:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE recipeml SYSTEM "recipeml.dtd">
<recipeml>
  <recipe>
    <head>
        <title>Coq au Riesling</title>
    </head>
    <ingredients>
        <ing>
            <amt>
                <qty>30</qty>
                <unit system="metric">ml</unit>
            </amt>
            <item>garlic-infused olive oil</item>
        </ing>
        <ing>
            <amt>
                <qty>150</qty>
                <unit system="metric" unit="g">gram(s)</unit>
            </amt>
            <item>bacon lardons</item>
        </ing>
        <ing>
            <amt>
                <qty>1</qty>
            </amt>
            <item>leek(s)</item>
            <prep>(finely sliced)</prep>
        </ing>
        <ing>
            <amt>
                <qty>12</qty>
            </amt>
            <item>chicken thighs (boneless and skinned)</item>
        </ing>
        <ing>
            <amt>
                <qty>3</qty>
            </amt>
            <item>bay leaves</item>
        </ing>
        <ing>
            <amt>
                <qty>300</qty>
                <unit system="metric">gram(s)</unit>
            </amt>
            <item>oyster mushroom(s) (torn into strips)</item>
        </ing>
        <ing>
            <amt>
                <qty>750</qty>
                <unit system="metric">ml</unit>
            </amt>
            <item>Riesling</item>
        </ing>
        <ing>
            <amt>
                <qty> 1</qty>
                <unit>splash of</unit>
            </amt>
            <item>double cream (optional)</item>
        </ing>
        <ing>
            <amt>
                <qty> 1</qty>
                <unit>pinch of</unit>
            </amt>
            <item>salt</item>
        </ing>
        <ing>
            <amt>
                <qty>1</qty>
                <unit>pinch of </unit>
            </amt>
            <item>Pepper</item>
        </ing>
        <ing>
            <amt>
                <qty>1</qty>
                <unit>tablespoon(s)</unit>
            </amt>
            <item>dill (chopped to serve (2 tablespoons if needed)) </item>
        </ing>
    </ingredients>

这是我的XSLT:

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

            </xsl:apply-templates>
        </body>          
    </html>
</xsl:template>
<xsl:template match="recipeml/recipe/head/title">
    <h3>
        <xsl:value-of select="."/>
    </h3>        
</xsl:template>
<xsl:template match="recipeml/recipe/ingredients">
    <ul> 
        <xsl:for-each select="ing">
            <li><xsl:value-of select="item"/>
                <ul><xsl:value-of select="//amt/child::qty[not(following-sibling::unit)]"/></ul></li>
        </xsl:for-each>
    </ul> 
</xsl:template>
<xsl:template match="recipeml/recipe/directions">
    <xsl:for-each select="*[not(preceding-sibling::step)]"/>
    <xsl:for-each select="*[not(following-sibling::note)]"/>
</xsl:template>

我的问题是在这里。我希望它仅在没有单位元素的情况下显示数量。我测试了我的xpath并成功了,但是当我应用我的场景时,它假定每个项目的数量为1。

    <ul><xsl:value-of select="//amt/child::qty[not(following-sibling::unit)]"/></ul></li>

这是我得到的输出:

    <html>
      <body>  

  <h3>Coq au Riesling</h3>


  <ul>
     <li>garlic-infused olive oil
        <ul>1</ul>
     </li>
     <li>bacon lardons
        <ul>1</ul>
     </li>
     <li>leek(s)
        <ul>1</ul>
     </li>
     <li>chicken thighs (boneless and skinned)
        <ul>1</ul>
     </li>
     <li>bay leaves
        <ul>1</ul>
     </li>
     <li>oyster mushroom(s) (torn into strips)
        <ul>1</ul>
     </li>
     <li>Riesling
        <ul>1</ul>
     </li>
     <li>double cream (optional)
        <ul>1</ul>
     </li>
     <li>salt
        <ul>1</ul>
     </li>
     <li>Pepper
        <ul>1</ul>
     </li>
     <li>dill (chopped to serve (2 tablespoons if needed)) 
        <ul>1</ul>
     </li>
  </ul>

我需要更改使其仅显示韭菜,鸡大腿和月桂叶的amt吗?

2 个答案:

答案 0 :(得分:0)

以“ /”或“ //”开头的路径表达式总是从树的根中选择。你写

<xsl:for-each select="ing">
   <li><xsl:value-of select="item"/>
       <ul><xsl:value-of select="//amt/child::qty[not(following-sibling::unit)]"/></ul></li>
</xsl:for-each>

但是amting的子代,因此您只想要select="amt/qty[...]"。您也可以写select="amt[not(unit)]/qty"

(顺便提一下,您的问题为我们提供了答案的线索。在一个上下文中正确的XPath表达式在另一个上下文中可能是完全错误的。了解XSLT如何更改上下文节点以评估XPath表达式至关重要。)

顺便说一句您的最后一个模板规则:

<xsl:template match="recipeml/recipe/directions">
    <xsl:for-each select="*[not(preceding-sibling::step)]"/>
    <xsl:for-each select="*[not(following-sibling::note)]"/>
</xsl:template>

将永远不会产生任何输出。这两个xsl:for-each指令为空,因此您说的是“对于每个xxxx,什么也不做”-始终不执行任何操作。

答案 1 :(得分:0)

考虑使用模板进行调整,以使模板沿树(食谱级别,成分级别, ing 级别)走下端对 ing 节点应用了两个集合。

使用这种方法,可以避免从根recipeml匹配多个模板,使用xsl:foreach,使用following-sibling以及使用//进行绝对引用。并确保添加<xsl:strip-space>来从源XML中删除空格和换行符。

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

    <xsl:template match="recipeml/recipe">
        <html>
            <body>
                <h3>
                    <xsl:value-of select="head/title"/>
                </h3>       
                <xsl:apply-templates select="ingredients"/>
            </body>          
        </html>
    </xsl:template>

    <xsl:template match="ingredients">
        <xsl:apply-templates select="ing[not(amt/unit)]"/>
        <xsl:apply-templates select="ing[amt/unit]"/>
    </xsl:template>

    <xsl:template match="ing[not(amt/unit)]">
        <ul> 
            <li><xsl:value-of select="item"/>
                <ul>
                    <xsl:value-of select="amt/qty"/>
                </ul>
            </li>
        </ul> 
    </xsl:template>

    <xsl:template match="ing[amt/unit]">
        <ul> 
            <li><xsl:value-of select="item"/>
            </li>
        </ul> 
    </xsl:template>

</xsl:stylesheet>

XSLT Fiddle Demo