Xml查找表

时间:2013-06-24 14:25:00

标签: xslt xpath-2.0

我试图在xml中使用查找表进行xsl转换。我熟悉xsl并且不关心查找表的物理加载和查询,而是我在编写具有稀疏填充查找的适当XPath时遇到了麻烦。

如果缺少lookup属性,我将使用一个需要回退到默认值的表。以下xml是此人口的一个示例:

<?xml version="1.0" encoding="UTF-8"?>
<codes>
    <code id="12" country="ca" areacode="420" division="45"/>
    <code id="13" country="ca" areacode="519" division="45"/>
    <code id="14" country="ca" areacode="519" division="40"/>
    <code id="15" country="ca" division="46"/>
    <code id="16" country="ca"/>
    <code id="17" country="au"/>
    <code id="18" country="au" division="32"/>
</codes>

在进行查找时,我会输入国家,地区代码和分部以找到合适的ID。

我尝试了几种选择,但没有一种是令人满意的。下面的XPath将返回两个条目(我应该得到15的id):

/codes/code[@country='ca' and (@areacode='222' or empty(@areacode)) and (@division='46' or empty(@division))]/@id

我的xsl支持XPath 2.0。

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:3)

如果我正确理解您的要求,那么@country始终存在,因此我们可以对该属性进行基于密钥的查找。对于其他两个属性@areacode@division,您需要使用code,其中两个属性都优先于code,而code具有一个匹配属性,优先级高于{{ 1}}没有匹配的属性。

所以我只想创建一个不同优先级的序列,然后找到第一个:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:param name="lkp-url" select="'test2013062402.xml'"/>
<xsl:variable name="lkp-doc" select="doc($lkp-url)"/>

<xsl:key name="by-country"
         match="code"
         use="@country"/>

<xsl:param name="c" select="'ca'"/>
<xsl:param name="ac" select="'222'"/>
<xsl:param name="d" select="'46'"/>

<xsl:template match="/">
  <xsl:value-of select="(key('by-country', $c, $lkp-doc)[@areacode = $ac and @division = $d],
                        key('by-country', $c, $lkp-doc)[not(@areacode) and @division = $d],
                        key('by-country', $c, $lkp-doc)[@areacode = $ac and not(@division)],
                        key('by-country', $c, $lkp-doc)[not(@areacode) and not(@division)])[1]/@id"/>
</xsl:template>

</xsl:stylesheet>

我不知道这两个属性中哪一个具有优先级,如果areacode具有优先权,您可能想要在代码中创建的序列中对第二和第三项进行随机播放。

上述代码应缩短为

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:param name="lkp-url" select="'test2013062402.xml'"/>
<xsl:variable name="lkp-doc" select="doc($lkp-url)"/>

<xsl:key name="by-country"
         match="code"
         use="@country"/>

<xsl:param name="c" select="'ca'"/>
<xsl:param name="ac" select="'222'"/>
<xsl:param name="d" select="'46'"/>

<xsl:template match="/">
  <xsl:variable name="cs" select="key('by-country', $c, $lkp-doc)"/>
  <xsl:value-of select="($cs[@areacode = $ac and @division = $d],
                        $cs[not(@areacode) and @division = $d],
                        $cs[@areacode = $ac and not(@division)],
                        $cs[not(@areacode) and not(@division)])[1]/@id"/>
</xsl:template>

</xsl:stylesheet>