如何遍历多个交叉引用?(How to iterate multiple cross-referenc

2019-10-18 08:31发布

我的XML源指定交叉引用linkGrp 。 基于由@target属性指定的那些交叉引用,我需要组的值s元件。 如果目标属性包含一到一个参考,我的代码有很好的作品如下:

<DIV>
    <div id="e">
        <s id="e1">AAAAA</s>
        <s id="e2">BBBBB</s>
        <s id="e3">CCCCC</s>
    </div>
    <div id="fr">
        <s id="fr1">DDDDD</s>
        <s id="fr2">EEEEE</s>
        <s id="fr3">FFFFF</s>
    </div>
    <linkGrp type="alignment" domains="e fr">
        <link target="#e1 #fr1"/>
        <link target="#e2 #fr3"/>
        <link target="#e3 #fr2"/>
    </linkGrp>
</DIV>

所请求的HTML输出我得到的是这样的:

*AAAAA
DDDDD

*BBBBB
FFFFF

*CCCCC
EEEEE

为了得到这样的结果我用下面的XSLT代码:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="linkId" match="s" use="@id"/>
    <xsl:template match="/DIV">
        <html>
            <head>
                <title>Test</title>
            </head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="link">
        <ul>
            <li>
                <xsl:value-of select="key('linkId',substring-before(substring-after(@target, '#'), ' '))"/>
                <br/>
                <xsl:value-of select="key('linkId',substring-after(@target, ' #'))"/>
            </li>
        </ul>
    </xsl:template>
    <xsl:template match="div"/>
    <xsl:template match="s"/>
    <xsl:template match="*">
        <xsl:message terminate="no">
            WARNING: Unmatched element: <xsl:value-of select="name()"/>
        </xsl:message>
        <xsl:apply-templates/>
    </xsl:template>
</xsl:stylesheet>

然而,当我在一个@target添加更多的交叉引用我的XSLT代码不工作那么好link元素这样的:

<DIV>
    <div id="e">
        <s id="e1">AAAAA</s>
        <s id="e2">BBBBB</s>
        <s id="e3">CCCCC</s>
    </div>
    <div id="fr">
        <s id="fr1">DDDDD</s>
        <s id="fr2">EEEEE</s>
        <s id="fr3">FFFFF</s>
    </div>
    <linkGrp type="alignment" domains="e fr">
        <link target="#e1 #fr1"/>
        <link target="#e2 #fr3 #fr1 #fr2"/>
        <link target="#e3 #fr2 #fr3"/>
    </linkGrp>
</DIV>

随着XML源中多个交叉引用,我的XSLT代码不取任何比赛。 我需要我的代码来检索指定的所有比赛@target属性。 任何人都能指出的错误在我的XSLT代码或提供替代解决方案?

Answer 1:

使用XSLT-1.0你可以使用递归调用模板分裂的ID。 尝试是这样的:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="linkId" match="s" use="@id"/>
    <xsl:template match="/DIV">
        <html>
            <head>
                <title>Test</title>
            </head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="link">
        <ul>
            <li>
                <xsl:call-template name="findtarget">
                    <xsl:with-param name="targets" select="@target" />
                </xsl:call-template>
            </li>
        </ul>
    </xsl:template>


    <xsl:template name="findtarget">
        <xsl:param name="targets" />
        <xsl:choose>
            <xsl:when test="contains($targets, ' ')">
                <xsl:call-template name="findtarget">
                    <xsl:with-param name="targets" select="substring-before($targets,' ')" />
                </xsl:call-template>
                <br/>
                <xsl:call-template name="findtarget">
                    <xsl:with-param name="targets" select="substring-after($targets,' ')" />
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="key('linkId',substring-after($targets, '#'))"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="div"/>
    <xsl:template match="s"/>
    <xsl:template match="*">
        <xsl:message terminate="no">
            WARNING: Unmatched element: <xsl:value-of select="name()"/>
        </xsl:message>
        <xsl:apply-templates/>
    </xsl:template>
</xsl:stylesheet>

这将产生以下的输出:

                     WARNING: Unmatched element: linkGrp
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test</title>
</head>
<body>



                <ul><li>AAAAA<br>DDDDD</li></ul>
                <ul><li>BBBBB<br>FFFFF<br>DDDDD<br>EEEEE</li></ul>
                <ul><li>CCCCC<br>EEEEE<br>FFFFF</li></ul>

</body>
</html>

另一种解决方案可以是使用XPath函数id() 但要使它工作的XML需要有一个DTD DOCTYPE。 事情是这样的:

<!DOCTYPE DIV  [
<!ATTLIST s
  id     ID    #REQUIRED
>
]>
<DIV>
    <div id="e">
        <s id="e1">AAAAA</s>
        <s id="e2">BBBBB</s>
        <s id="e3">CCCCC</s>
    </div>
    <div id="fr">
        <s id="fr1">DDDDD</s>
        <s id="fr2">EEEEE</s>
        <s id="fr3">FFFFF</s>
    </div>
    <linkGrp type="alignment" domains="e fr">
        <link target="#e1 #fr1"/>
        <link target="#e2 #fr3 #fr1 #fr2"/>
        <link target="#e3 #fr2 #fr3"/>
    </linkGrp>
</DIV>

有了这个XML您的链接模板可能变化如下:

<xsl:template match="link">
    <ul>
        <li>
            <xsl:for-each select="id(translate(@target,'#', ''))">
                <xsl:if test="position() > 1">
                    <br/>
                </xsl:if>
                <xsl:value-of select="."/>
            </xsl:for-each>
        </li>
    </ul>
</xsl:template>


文章来源: How to iterate multiple cross-references?
标签: xml xslt