使用XSL函数动态检索XML值

时间:2010-08-25 18:37:08

标签: xml xslt xpath xslt-2.0

我的输入xml文件看起来像

<root>
  <sub>
    <element1 value="abc"/>
        <element2 value="123"/>
  </sub>
  <sub1>
    <element1 value="ert"/>
    <element2 value="abc"/>
  </sub1>
</root>

我需要一个XSLT函数,它在XML文件下面读取并从上面的文件中提取map / domain / instance / @ xpath中指定的xpath表达式值

<map>
  <domain>
    <instance xpath="root/sub/element1/@value" length="2"/>
  </domain>
  <domain>
        <instance xpath="root/sub1/element2/@value" length="3"/>
  </domain>
</map>

我需要一个xslt函数,它根据传入的xml文件检查为每个xpath表达式指定的长度。

如果长度不合适,则应该返回错误。

1 个答案:

答案 0 :(得分:3)

这个XSLT 1.0样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="document">
        <root>
            <sub>
                <element1 value="abc"/>
                <element2 value="123"/>
            </sub>
            <sub1>
                <element1 value="ert"/>
                <element2 value="abc"/>
            </sub1>
        </root>
    </xsl:variable>
    <xsl:template match="map/domain/instance" name="walker">
        <xsl:param name="path" select="@xpath"/>
        <xsl:param name="context"
               select="document('')/*/xsl:variable[@name='document']"/>
        <xsl:choose>
            <xsl:when test="contains($path,'/')">
                <xsl:call-template name="walker">
                    <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:when test="starts-with($path,'@')">
                <xsl:value-of select="concat(
                                        string-length(
                                          $context/attribute::*
                                             [name()=substring($path,2)])
                                        =@length,
                                        '&#xA;')"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="concat(
                                        string-length(
                                          $context/*[name()=$path])
                                        =@length,
                                        '&#xA;')"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

输出:

false
true

编辑:XSLT 2.0解决方案。这个样式表:

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="example.org">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>
    <xsl:variable name="document">
        <root>
            <sub>
                <element1 value="abc"/>
                <element2 value="123"/>
            </sub>
            <sub1>
                <element1 value="ert"/>
                <element2 value="abc"/>
            </sub1>
        </root>
    </xsl:variable>
    <xsl:template match="map/domain/instance">
        <xsl:sequence select="my:xpath(@xpath,$document)
                                   /string(string-length() =
                                           current()/@length)"/>
        <xsl:text>&#xA;</xsl:text>
    </xsl:template>
    <xsl:function name="my:xpath" as="item()*">
        <xsl:param name="path" as="xs:string"/>
        <xsl:param name="context" as="node()*"/>
        <xsl:variable name="steps" as="item()*"
                      select="tokenize($path,'/')"/>
        <xsl:variable name="this" as="item()*"
                      select="$context/(*[if ($steps[1]='*')
                                          then true()
                                          else name()=$steps[1]]|
                                        @*[if ($steps[1]='@*')
                                          then true()
                                          else name() =
                                               substring($steps[1],2)])"/>
        <xsl:choose>
            <xsl:when test="count($steps)>1">
                <xsl:sequence
                    select="my:xpath(string-join($steps[position()!=1],
                                                 '/'),
                                     $this)"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:sequence select="$this"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:function>
</xsl:stylesheet>

输出:

false
true

编辑2 :有点改进。现在,通过这个输入:

<map>
    <domain>
        <instance xpath="root/sub/element1/@*" length="2"/>
    </domain>
    <domain>
        <instance xpath="root/sub/*/@value" length="3"/>
    </domain>
</map>

输出:

false
true true