0

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

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

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

我一开始就遵循w3school 教程。我是 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>
4

2 回答 2

2

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

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

这意味着所有子元素,除非另有说明,都属于该命名空间。但是,在您的 XSLT 中,根本没有对此命名空间的引用,因此 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”纯粹是任意的,它可以是任何东西。

于 2012-06-01T06:32:11.273 回答
0

要回答您的第三个问题“我怎样才能摆脱内置模板?”

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

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

有关详细信息,请参阅Microsoft 关于内置模板的说明。

(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>
于 2012-06-01T07:04:22.293 回答