使用XML数据动态生成XPath表达式

时间:2010-05-21 20:26:57

标签: xml xslt dynamic xpath

我想在由XML文件中的数据确定的XSL中动态创建XPath表达式。 (即XML数据被“连接”以创建XPath表达式)。

XML数据示例:

<criteria>
    <criterion>AAA</criterion>
    <criterion>BBB</criterion>
    <criterion>CCC</criterion>
</criteria>

我希望XPath表达式如何显示的示例:

//AAA | //BBB | //CCC

这个动态生成需要在XSL文件中完成。

我对XSL(和家人)相当陌生,并希望了解如何解决这个问题。

谢谢!

编辑: 提供更多背景.... 我需要做的是生成一个XPath,用于创建一个第二个 XSL,它转换完全不同的XML文件。我知道如何从XSL创建XSL,我只需要动态创建XPath表达式。如果我可以修改变量(我从其他地方读取,我不能),我只是将节点连接在一起形成一个表达式。然后从那里我将使用变量名称,无论我需要它。不幸的是我不能这样做.. :(

3 个答案:

答案 0 :(得分:3)

以下将创建示例XPATH字符串作为针对示例XML文件运行时“generatedXPATH”变量的值:

    <xsl:variable name="generatedXPATH">
        <xsl:for-each select="/criteria/criterion">
            <xsl:text>//</xsl:text>
            <xsl:value-of select="." />
            <xsl:if test="position()!=last()">
                <xsl:text> | </xsl:text>
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>

您可以在样式表中使用该变量来生成样式表,以构建模板@match这样的值:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xslt="http://www.w3.org/1999/XSL/TransformAlias"
    version="1.0">
    <xsl:namespace-alias stylesheet-prefix="xslt" result-prefix="xsl"/>
    <xsl:output indent="yes" />
    <xsl:template match="/">
        <xsl:variable name="generatedXPATH">
            <xsl:for-each select="/criteria/criterion">
                <xsl:text>//</xsl:text>
                <xsl:value-of select="." />
                <xsl:if test="position()!=last()">
                    <xsl:text> | </xsl:text>
                </xsl:if>
            </xsl:for-each>
        </xsl:variable>

        <xslt:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
            <xslt:template>
                <xsl:attribute name="match">
                    <xsl:value-of select="$generatedXPATH" />
                </xsl:attribute>
                <xsl:comment>Do something special, like select the value of the matched elements</xsl:comment>
                <xslt:value-of select="." />
            </xslt:template>
        </xslt:stylesheet>
    </xsl:template>

</xsl:stylesheet>

针对示例运行时,XML会生成此样式表:

<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="//AAA | //BBB | //CCC">
<!--Do something special, like select the value of the matched elements-->
<xsl:value-of select="." />
</xsl:template>
</xsl:stylesheet>

答案 1 :(得分:2)

可以在XSLT中动态创建XPath表达式,但不能对这些表达式进行动态评估(至少在XSLT 2.1之前)。

您可以在XSLT中以其他方式完成所需的操作。

以下是一个例子:

这种转变:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my"
 >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <my:criteria>
  <criterion>a</criterion>
  <criterion>b</criterion>
  <criterion>c</criterion>
 </my:criteria>

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

 <xsl:template match="*[name()=document('')/*/my:criteria/*]">
   <xsl:element name="{name()}-{name()}" namespace="{namespace-uri()}">
     <xsl:apply-templates select="node()|@*"/>
   </xsl:element>
 </xsl:template>
</xsl:stylesheet>

应用于此XML文档时

<t>
  <a>
    <x/>
    <y/>
    <b>
      <c/>
      <d/>
    </b>
  </a>
</t>

<强>产生

<t>
    <a-a>
        <x></x>
        <y></y>
        <b-b>
            <c-c></c-c>
            <d></d>
        </b-b>
    </a-a>
</t>

也就是说,我们只以特殊方式处理任何元素(文档中的任何位置),其名称为abc

答案 2 :(得分:0)

您无法使用xsl或xpath动态执行此操作。你将不得不使用PHP或其他(取决于你在哪里使用它)。如果您有一组有限的节点,则可以使用// AAA | // BBB | // CCC它会起作用,但如果你想让它在许多不同的节点上工作,那么它并没有用。

有关XPath的更多信息,请参阅here

编辑: Jeez,你编辑过它。

使用/ criteria / [criterion = AAA]。

再次编辑:

查询应为:“/criteria/[criterion=AAA] | criteria/[criterion=BBB] | criteria/[criterion=CCC]”。虽然我忘了怎么做,你可能会改写这个更有效率。请参阅this tutorial,了解它是如何完成的。希望有所帮助。