在XSLT中编写xsl:value-of的正确方法

时间:2012-06-01 06:06:17

标签: xml visual-studio-2010 xslt xpath

我正在尝试编写XSLT以将XML从一种格式转换为另一种格式。当我将.xslt文件应用于VS 2010中的XML文件时,创建了输出XML结构,没有任何问题。但它并未填写处理xsl:value-of预期的数据。

当我使用XMLSpy并评估XPath表达式时,对于以下XSLT中的表达式,它会显示no result。但是当我在XPath表达式的末尾使用node()函数时,它会显示值!

  1. 编写XPath的正确方法是什么?
  2. 每次读取元素内容(没有子元素时)是否真的需要node()text()种函数?如果不是,为什么XmlSpy也没有给出没有这些函数的结果?
  3. 有时(当我在调试XSLT时将模板匹配值从“/”更改为“ServiceMessage”),VS 2010会进入内置模板规则。为什么会这样?如何摆脱VS 2010中的内置模板?
  4. 我开始关注w3school tutorial。我是XSLT的新手。

    这是我想要转换为其他XML格式的XML。

    <ServiceMessage xmlns="http://requestservice/requests" xmlns:req="http://requestservice/requests/xmlstds">
    
    <TypeOfReq> General </TypeOfReq>
    <Details>
       <Id> 123456789 </Id>
       <SenderDetails>
            <Sender id="345"></Sender>
       </SenderDetails>
    </Details>
    
    </ServiceMessage>
    

    这是我的XSLT

    <?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="/">
        <request>
          <requestType>
            <xsl:value-of select="ServiceMessage/TypeOfReq" />
          </requestType>
          <Id>
            <xsl:value-of select="ServiceMessage/Details/Id"/>
          </Id>
          <senderId>
            <xsl:value-of select="ServiceMessage/Details/SenderDetails/Sender/@id"/>
          </senderId>
        </request>
    
      </xsl:template>
    
    
    
    </xsl:stylesheet>
    

2 个答案:

答案 0 :(得分:2)

您已从合成的角度正确编写了xpath。您实际遇到的问题实际上与名称空间有关。在XML中,您指定了一个默认命名空间

<ServiceMessage xmlns="http://requestservice/requests">

这意味着除非另有说明,否则所有子元素都属于该命名空间。但是,在您的XSLT中,根本没有对此namepsace的引用,因此XSLT正在查找未指定命名空间的元素。您的XML不是这种情况。

对于XSLT 1.0,您需要声明命名空间,如下所示:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:s="http://requestservice/requests"> 

然后,您将明确说明它用于匹配元素的位置

<xsl:value-of select="s:ServiceMessage/s:TypeOfReq" />

这是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:s="http://requestservice/requests">
   <xsl:output method="xml" indent="yes"/>
   <xsl:template match="/">
      <request>
         <requestType>
            <xsl:value-of select="s:ServiceMessage/s:TypeOfReq"/>
         </requestType>
         <Id>
            <xsl:value-of select="s:ServiceMessage/s:Details/s:Id"/>
         </Id>
         <senderId>
            <xsl:value-of select="s:ServiceMessage/s:Details/s:SenderDetails/s:Sender/@id"/>
         </senderId>
      </request>
   </xsl:template>
</xsl:stylesheet>

应用于XML时,输出以下内容

<request xmlns:s="http://requestservice/requests">
   <requestType> General </requestType>
   <Id> 123456789 </Id>
   <senderId>345</senderId>
</request>

请注意,这里字母's'的选择纯粹是武断的,它可能是真的。

答案 1 :(得分:0)

回答第3个问题“如何摆脱内置模板?”

如果您没有为xml中出现的元素指定模板,在您的情况下,VS将应用身份模板,这只会将源元素复制到您的输出。

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

有关详细信息,请参阅Microsoft's explanation on built in templates

(atm我不知道是否可以关闭它,因为我这里只有VS Express,它不提供Xslt调试)

作为一般规则,您应始终为要处理的所有元素指定模板,因此您的基本xslt始终以

开头
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:s="http://requestservice/requests">

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

</xsl:stylesheet>

接下来,在您的情况下,为根元素添加模板 ServiceMessage

<xsl:template match="s:ServiceMessage">
    <!-- usually apply-templates, in your case create new output element(s) -->
<xsl:template>