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

时间:2022-11-23 08:26:33

I would like to dynamically create XPath expressions in an XSL determined by data in an XML file. (i.e. the XML data is "concatenated" to create an XPath expression).

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

Example of XML data:

XML数据示例:

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

Example of how I would like the XPath expression to look like:

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

//AAA | //BBB | //CCC

And this dynamic generation needs to be done in an XSL file.

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

I am fairly new to XSL (and family) and would appreciate some general direction on how to tackle this problem.

我对XSL(和家人)来说还是个新手,我很欣赏如何解决这个问题的一般方向。

Thanks!

Edit: To provide a little more context.... What I need to do is generate an XPath to be used to create a second XSL which transforms an entirely different XML file. I know how to create an XSL from an XSL, I just need to dynamically create XPath expressions. If I could modify variables (which I read from somewhere else I can't) I would just keep concatenating nodes together to form an expression. Then from there I would use the variable name wherever I needed it. Unfortunately I can't do this though.. :(

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

3 个解决方案

#1


3  

The following will create the sample XPATH string as the value of the "generatedXPATH" variable when run against the sample XML file:

以下将创建示例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>

You could use that variable in a stylesheet that produces a stylesheet to construct the template @match values like this:

您可以在生成样式表的样式表中使用该变量来构造模板@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>

When run against the sample XML produces this 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>

#2


2  

It is possible to create XPath expressions dynamically in XSLT, but no dynamic evaluation of these expressions is possible (at least until XSLT 2.1).

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

What you want can be done in another way in XSLT.

你想要什么可以在XSLT中以另一种方式完成。

Here is an example:

这是一个例子:

This transformation:

<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>

when applied on this XML document:

应用于此XML文档时:

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

produces:

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

That is, we only processed in a special way any element (anywhere in the document), whose name was a or b or c.

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

#3


0  

You cannot dynamically do that with xsl or xpath. You'll have to use php or whatever (depends on where you're using this). If you have a limited set of nodes, you can use //AAA | //BBB | //CCC and it will work, though this is not really usefull if you want it to work on lots of different nodes.

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

See here for more info on XPath.

有关XPath的更多信息,请参见此处。

Edit: Jeez, you edited it.

编辑:Jeez,你编辑过它。

Use /criteria/[criterion=AAA] for that.

使用/ criteria / [criterion = AAA]。

Edit again:

the query should be: "/criteria/[criterion=AAA] | criteria/[criterion=BBB] | criteria/[criterion=CCC]". You can probably rephrase this to be more efficient though i forgot how. See this tutorial to see how it's done. Hope that helps.

查询应该是:“/ criteria / [criterion = AAA] | criteria / [criterion = BBB] | criteria / [criterion = CCC]”。你可能会改写这个更有效但我忘了怎么做。请参阅本教程以了解它是如何完成的。希望有所帮助。

#1


3  

The following will create the sample XPATH string as the value of the "generatedXPATH" variable when run against the sample XML file:

以下将创建示例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>

You could use that variable in a stylesheet that produces a stylesheet to construct the template @match values like this:

您可以在生成样式表的样式表中使用该变量来构造模板@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>

When run against the sample XML produces this 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>

#2


2  

It is possible to create XPath expressions dynamically in XSLT, but no dynamic evaluation of these expressions is possible (at least until XSLT 2.1).

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

What you want can be done in another way in XSLT.

你想要什么可以在XSLT中以另一种方式完成。

Here is an example:

这是一个例子:

This transformation:

<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>

when applied on this XML document:

应用于此XML文档时:

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

produces:

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

That is, we only processed in a special way any element (anywhere in the document), whose name was a or b or c.

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

#3


0  

You cannot dynamically do that with xsl or xpath. You'll have to use php or whatever (depends on where you're using this). If you have a limited set of nodes, you can use //AAA | //BBB | //CCC and it will work, though this is not really usefull if you want it to work on lots of different nodes.

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

See here for more info on XPath.

有关XPath的更多信息,请参见此处。

Edit: Jeez, you edited it.

编辑:Jeez,你编辑过它。

Use /criteria/[criterion=AAA] for that.

使用/ criteria / [criterion = AAA]。

Edit again:

the query should be: "/criteria/[criterion=AAA] | criteria/[criterion=BBB] | criteria/[criterion=CCC]". You can probably rephrase this to be more efficient though i forgot how. See this tutorial to see how it's done. Hope that helps.

查询应该是:“/ criteria / [criterion = AAA] | criteria / [criterion = BBB] | criteria / [criterion = CCC]”。你可能会改写这个更有效但我忘了怎么做。请参阅本教程以了解它是如何完成的。希望有所帮助。