使用XPath生成XPath
问题描述:
我有两种不同类型的XML文档(一种是a.xml
&另一种是b.xml
)。文档a.xml
,是我的主要源文件,我必须运行查询。文档b.xml
包含从a.xml
获取记录的所有可能的信息。使用XPath生成XPath
文件:«A.XML»
<rs>
<r id="r1">
<f0>typeA</f0>
<f1>contains value1, value2 and value3</f1>
</r>
<r id="r2">
<f0>typeB</f0>
<f1>contains value4 and value7</f1>
</r>
<r id="r3">
<f0>typeA</f0>
<f1>contains value2 and value5</f1>
</r>
<r id="r4">
<f0>typeC</f0>
<f1>contains value1 and value6</f1>
</r>
<r id="r5">
<f0>typeA</f0>
<f1>contains value5</f1>
</r>
<r id="r6">
<f0>typeC</f0>
<f1>contains value1, value2 and value3</f1>
</r>
</rs>
文件:«B.XML»
<?xml version="1.0"?>
<qs>
<q id="q1">
<i0>typeA</i0>
<i1>value1|value2|value3</i1>
<i2>value18|value35</i2>
<i3>value1|value7</i3>
</q>
<q id="q2">
<i0>typeB</i0>
<i1>value2|value7</i1>
<i2>value9|value20</i2>
<i3>value4</i3>
</q>
</qs>
现在我想生成动态XPath selector strings
基于b.xml
的值存储在文档c.xml
中。它看起来像:
文件c.xml
<xps>
<xp id="q1">
<t1>/rs/r[contains(f0,'typeA')
and contains(f1,'value1')
and contains(f1,'value2')
and contains(f1,'value3')]</t1>
<t2>/rs/r[contains(f0,'typeA')
and contains(f1,'value18')
and contains(f1,'value35')]</t2>
<t3>/rs/r[contains(f0,'typeA')
and contains(f1,'value1')
and contains(f1,'value7')]</t3>
</xp>
<xp id="q2">
<t1>/rs/r[contains(f0,'typeB')
and contains(f1,'value2')
and contains(f1,'value7')]</t1>
<t2>/rs/r[contains(f0,'typeA')
and contains(f1,'value9')
and contains(f1,'value20')]</t2>
<t3>/rs/r[contains(f0,'typeA')
and contains(f1,'value4')]</t3>
</xp>
</xps>
如果有人在这里有任何想法,如何做到在XSLT 1.0版本的工作。提前致谢。
答
这里是XSLT 1.0的解决方案:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="@*|text()" />
<xsl:template match="/">
<xps>
<xsl:apply-templates/>
</xps>
</xsl:template>
<xsl:template match="q">
<xp id="{@id}">
<xsl:apply-templates/>
</xp>
</xsl:template>
<xsl:template match="*[starts-with(name(), 'i')][not(self::i0)]">
<xsl:element name="t{substring-after(name(), 'i')}">
<xsl:text>/rs/r[contains(f0, '</xsl:text>
<xsl:value-of select="preceding-sibling::i0"/>
<xsl:text>')</xsl:text>
<xsl:call-template name="more-conditions">
<xsl:with-param name="list" select="."/>
</xsl:call-template>
<xsl:text>]</xsl:text>
</xsl:element>
</xsl:template>
<xsl:template name="more-conditions">
<xsl:param name="list"/>
<xsl:param name="delimiter" select="'|'"/>
<xsl:choose>
<xsl:when test="contains($list, $delimiter)">
<xsl:call-template name="more-conditions">
<xsl:with-param name="list" select="substring-before($list, $delimiter)"/>
</xsl:call-template>
<xsl:call-template name="more-conditions">
<xsl:with-param name="list" select="substring-after($list, $delimiter)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:text> and contains(f1, '</xsl:text>
<xsl:value-of select="$list"/>
<xsl:text>')</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
适用于您的输入文档,它产生以下输出:
<xps>
<xp id="q1">
<t1>/rs/r[contains(f0, 'typeA') and contains(f1, 'value1') and contains(f1, 'value2') and contains(f1, 'value3')]</t1>
<t2>/rs/r[contains(f0, 'typeA') and contains(f1, 'value18') and contains(f1, 'value35')]</t2>
<t3>/rs/r[contains(f0, 'typeA') and contains(f1, 'value1') and contains(f1, 'value7')]</t3>
</xp>
<xp id="q2">
<t1>/rs/r[contains(f0, 'typeB') and contains(f1, 'value2') and contains(f1, 'value7')]</t1>
<t2>/rs/r[contains(f0, 'typeB') and contains(f1, 'value9') and contains(f1, 'value20')]</t2>
<t3>/rs/r[contains(f0, 'typeB') and contains(f1, 'value4')]</t3>
</xp>
</xps>
我添加了一些空格。您可以根据需要修改转换,但这应该让您开始。
答
您不能在xslt版本1中将变量用作xpath选择器,但可能有其他方法可以完成此任务。如果您提供的问题,而不是您想要的解决方案的人的想法也许能帮助:)
+0
我想只生成''c.xml'',稍后根据该文件创建另一个XSL文件。但是,我只需要,只生成''c.xml''。 – Cylian 2012-04-27 04:05:49
真棒代码,非常感谢! – Cylian 2012-04-28 04:15:42