具有动态路径的 XSLT 文档

发布于 2024-12-18 02:54:52 字数 3558 浏览 0 评论 0原文

我有 XSLT 1.0 标准。 我有一个来自服务器的动态 XML,非常简单,第二个 XML 作为配置。基于第一个(动态的)我必须从第二个中获取正确的节点信息。 这是第一个文档:

<?xml version="1.0" encoding="UTF-8" ?>
<response>
    <response>SUCCESS</response>
    <responsedata>
        <hit>
            <url>http://domain.com/page.html</url>
            <id>2437</id>
            <title>Page title</title>
            <language>en</language>
            ...
            ...
        </hit>
    </responsedata>
</response>

第二个配置 XML 用于按语言划分的页脚、页眉。类似这样的事情:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <set id="local">
        <header>
            <en>
                <![CDATA[
<div id="header">
    <p>English code</p>
</div>
                ]]>
            </en>
            <fr>
                <![CDATA[
<div id="header">
    <p>French code</p>
</div>
                ]]>
            </fr>
        </header>
    </set>
</config>

我需要从第二个 XML 中选取正确的语言相关代码。 我尝试了以下代码,但它不起作用:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" omit-xml-declaration="yes" encoding="utf-8" indent="yes" doctype-system="about:legacy-compat" />
    <xsl:variable name="configuration" select="document('settings.xml')/config/set[@id='local']" />
    <xsl:variable name="lang" select="response/responsedata/hit/language" />

    <xsl:template name="getvalueofnode">
        <xsl:param name="path" />
        <xsl:param name="context" select="$configuration" />
        <xsl:choose>
            <xsl:when test="contains($path,'/')">
                <xsl:call-template name="getvalueofnode">
                    <xsl:with-param name="path"    
                        select="substring-after($path,'/')" />
                    <xsl:with-param name="context" 
                        select="$context/*[name()=substring-before($path,'/')]" />
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <p>value: <xsl:value-of select="$context/*[name()=$path]" disable-output-escaping="yes" /></p>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="/">
        <xsl:element name="html">
            <xsl:attribute name="lang"><xsl:value-of select="$lang" /></xsl:attribute>
            <xsl:element name="head">
                <xsl:attribute name="lang"><xsl:value-of select="$lang" /></xsl:attribute>
            </xsl:element>
            <xsl:element name="body">
                <xsl:attribute name="lang"><xsl:value-of select="$lang" /></xsl:attribute>
                <p>lang: <xsl:value-of select="$lang" /></p>
                <p>
                <xsl:call-template name="getvalueofnode">
                    <xsl:with-param name="path" select="concat('/header/',$lang)" />
                </xsl:call-template>
                </p>
            </xsl:element>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

如果有人有任何建议或解决方案,那就太棒了。

I have XSLT 1.0 standard.
I have one dynamic XML from server which is quite simple and second XML as configuration. Base on first one (which is dynamic) I have to pick up proper nodes information from second one.
This is first document:

<?xml version="1.0" encoding="UTF-8" ?>
<response>
    <response>SUCCESS</response>
    <responsedata>
        <hit>
            <url>http://domain.com/page.html</url>
            <id>2437</id>
            <title>Page title</title>
            <language>en</language>
            ...
            ...
        </hit>
    </responsedata>
</response>

Second configuration XML is for footer, header divided by languages. Something like that:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <set id="local">
        <header>
            <en>
                <![CDATA[
<div id="header">
    <p>English code</p>
</div>
                ]]>
            </en>
            <fr>
                <![CDATA[
<div id="header">
    <p>French code</p>
</div>
                ]]>
            </fr>
        </header>
    </set>
</config>

I need pick up proper language depended code from second XML.
I tried following code and it doesn't work:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" omit-xml-declaration="yes" encoding="utf-8" indent="yes" doctype-system="about:legacy-compat" />
    <xsl:variable name="configuration" select="document('settings.xml')/config/set[@id='local']" />
    <xsl:variable name="lang" select="response/responsedata/hit/language" />

    <xsl:template name="getvalueofnode">
        <xsl:param name="path" />
        <xsl:param name="context" select="$configuration" />
        <xsl:choose>
            <xsl:when test="contains($path,'/')">
                <xsl:call-template name="getvalueofnode">
                    <xsl:with-param name="path"    
                        select="substring-after($path,'/')" />
                    <xsl:with-param name="context" 
                        select="$context/*[name()=substring-before($path,'/')]" />
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <p>value: <xsl:value-of select="$context/*[name()=$path]" disable-output-escaping="yes" /></p>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="/">
        <xsl:element name="html">
            <xsl:attribute name="lang"><xsl:value-of select="$lang" /></xsl:attribute>
            <xsl:element name="head">
                <xsl:attribute name="lang"><xsl:value-of select="$lang" /></xsl:attribute>
            </xsl:element>
            <xsl:element name="body">
                <xsl:attribute name="lang"><xsl:value-of select="$lang" /></xsl:attribute>
                <p>lang: <xsl:value-of select="$lang" /></p>
                <p>
                <xsl:call-template name="getvalueofnode">
                    <xsl:with-param name="path" select="concat('/header/',$lang)" />
                </xsl:call-template>
                </p>
            </xsl:element>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

If some one has any suggestion or solution it will be fantastic.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

变身佩奇 2024-12-25 02:54:52

由于您已经知道基于 $lang 的元素名称,因此您可以完全消除 getvalueofnode 模板。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" omit-xml-declaration="yes" encoding="utf-8" indent="yes" doctype-system="about:legacy-compat" />
  <xsl:variable name="configuration" select="document('settings.xml')/config/set[@id='local']" />
  <xsl:variable name="lang" select="response/responsedata/hit/language" />

  <xsl:template match="/">
    <html lang="{$lang}">
      <head lang="{$lang}"/>
      <body lang="{$lang}">
        <p>lang: <xsl:value-of select="$lang" /></p>
        <p>value: <xsl:value-of disable-output-escaping="yes" select="$configuration/header/*[name()=$lang]"/></p>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

我还删除了所有 xsl:elementxsl:attribute。通常可以通过直接对元素进行编码并使用 AVT(属性值模板) 用于属性。

上面的样式表使用 XML 输入文件生成以下输出(使用 Saxon 6.5.5 和 Saxon-HE 9.3.0.5 进行测试):

<!DOCTYPE html
  SYSTEM "about:legacy-compat">
<html lang="en">
   <head lang="en">
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   </head>
   <body lang="en">
      <p>lang: en</p>
      <p>value: 

         <div id="header">
         <p>English code</p>
         </div>


      </p>
   </body>
</html>

Since you already know the name of the element based on $lang, you can eliminate the getvalueofnode template all together.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" omit-xml-declaration="yes" encoding="utf-8" indent="yes" doctype-system="about:legacy-compat" />
  <xsl:variable name="configuration" select="document('settings.xml')/config/set[@id='local']" />
  <xsl:variable name="lang" select="response/responsedata/hit/language" />

  <xsl:template match="/">
    <html lang="{$lang}">
      <head lang="{$lang}"/>
      <body lang="{$lang}">
        <p>lang: <xsl:value-of select="$lang" /></p>
        <p>value: <xsl:value-of disable-output-escaping="yes" select="$configuration/header/*[name()=$lang]"/></p>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

I also got rid of all the xsl:element and xsl:attribute. These can normally be avoided by coding the elements directly and using AVT (attribute value templates) for the attributes.

The stylesheet above produces the following output using your XML input files (tested with Saxon 6.5.5 and Saxon-HE 9.3.0.5):

<!DOCTYPE html
  SYSTEM "about:legacy-compat">
<html lang="en">
   <head lang="en">
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   </head>
   <body lang="en">
      <p>lang: en</p>
      <p>value: 

         <div id="header">
         <p>English code</p>
         </div>


      </p>
   </body>
</html>
一场信仰旅途 2024-12-25 02:54:52

我不太确定我是否正确地解决了你的问题,但我还是会尝试一下。

当您尝试使用 getvalueofnode 模板获取值时,您将提供 /header/en 作为路径。该模板将截断第一个斜杠之前的字符串,并在您的配置中查找具有该名称的元素。恰好被截断的值是空字符串,这会导致您的模板在配置中查找没有名称(不存在)的元素。

因此,在第二次调用(第一次递归调用)中,$content 将是一个空的结果树片段。因为它不包含斜杠,所以您的模板会打印不存在的值,因此也会打印一个空的结果树片段。由于空树片段在打印时会转换为空字符串,因此您的输出将是:

<p>value: </p>

关于解决方案:只需在第一次调用模板时删除前导斜杠即可。这就是用途:

<xsl:call-template name="getvalueofnode">
    <xsl:with-param name="path" select="concat('header/',$lang)" />
</xsl:call-template>

您的转换将产生英文标题。

顺便说一句,您对 getvalueofnode 的调用封装在

中,它返回值的地方也是如此。这会导致最终输出中出现嵌套的段落标签。

I'm not too sure if I got your problem correctly however I'll give it a try nevertheless.

When you try to get your value with the getvalueofnode template you are supplying /header/en as path. The template will the chop off the string before the first slash and look for an element with that name in your configuration. It happens to be that the chopped off value is the empty string which results in your template looking for an element in the configuration without a name (that does not exist).

$content will therefore be an empty result tree fragment in the second call (first recursive call). Because this doesn't contain a slash your template print the value that is not there and therefore an empty result tree fragment as well. Since empty tree fragments are converted to an empty string when printed your output will just be:

<p>value: </p>

Regarding a solution: Just remove the leading slash when calling your template for the first time. That's use:

<xsl:call-template name="getvalueofnode">
    <xsl:with-param name="path" select="concat('header/',$lang)" />
</xsl:call-template>

Your transformation will then result in the English header.

By the way your call to getvalueofnode is encapsulated in <p> and so is the place where it returns its value. This leads to nested paragraph tags in the final output.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文