希望找到一位大师的帮助来找出下一个问题。
我有两个xml文件。这里有第一个( text.xml ):
<text>
<ref>Author1, Title1, Date1</ref>
<ref>Author75, Title75, Date2</ref>
<ref>Author2, Title2, Date2</ref>
<ref>Author3, Title3, Date3</ref>
<text>
第二个像这样( list.xml ):
<list>
<bibl xml:id="1"><author>Author1</author><date>Date1</date></bibl>
<bibl xml:id="2"><author>Author2</author><date>Date2</date></bibl>
<bibl xml:id="3"><author>Author3</author><date>Date3</date></bibl>
</list>
我想查询 text.xml 并检查 list.xml 以将@xml:id(来自 list.xml )添加到<ref>
(来自 text.xml )包含相同的作者和日期。如果没有,则只需复制原始<ref>
。
所以我想获得:
<ref xml:id="1">Author1, Title1, Date1</ref>
<ref>Author75, Title75, Date2</ref>
<ref xml:id="2>Author2, Title2, Date2</ref>
etc.
我的 XSLT 很好地识别所有相关信息:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ref">
<xsl:variable name="ref" select="."/>
<xsl:for-each select="document('list.xml')//bibl">
<xsl:variable name="bibl" select="."/>
<xsl:variable name="author" select="author"/>
<xsl:variable name="date" select="date"/>
<xsl:choose>
<xsl:when test="contains($ref, $author) and contains($ref, $date)">
<ref>
<xsl:attribute name="xml:id">
<xsl:value-of select="$bibl/@xml:id"/>
</xsl:attribute>
<xsl:value-of select="$ref"/>
</ref>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$ref"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
但是,然后没有相应的不仅是复制权<ref>
,而是复制所有<ref>
我在第二个文件中拥有<bibl>
个节点的时间。
问题出在<xsl:otherwise><xsl:copy-of select="$ref"/></xsl:otherwise>
。
任何想法我如何才能获得我需要的这个独特的价值?我知道它实际上必须非常简单,我尝试使用key,generate-id,for-each-groups,distinct-values,但无法弄明白。
答案 0 :(得分:0)
编辑:
嗯......过分关注xsl语法,我应该早点看到......
每个ref
上都有一个牵连的外循环,每个bibl
上都有一个内循环。无论是匹配还是不匹配,您为每bibl
个ref
生成一个元素。
因此,代替xsl:otherwise
,您需要在for-each
循环后检查是否没有匹配,如果需要,请执行copy-of
。
不确定如何进行检查,但是..可能使用生成的position()
的{{1}}和count()
,对不起...没有时间去思考关于这一点。
<击> 不是解释,而是解决方法:
<ref>
我的猜测是问题在于$ ref,那时候不是xpath表达式(如果我正确记得xsl-t)
击>
答案 1 :(得分:0)
问题在于,无论是否存在匹配,您都要为 for-each 循环的每次迭代创建 ref 元素。
在这种情况下,您需要做的是在 for-each 之外创建 ref 元素,然后只为循环内的匹配元素创建id属性
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ref">
<xsl:variable name="ref" select="."/>
<ref>
<xsl:apply-templates select="@* "/>
<xsl:for-each select="document('list.xml')//bibl">
<xsl:variable name="bibl" select="."/>
<xsl:variable name="author" select="author"/>
<xsl:variable name="date" select="date"/>
<xsl:choose>
<xsl:when test="contains($ref, $author) and contains($ref, $date)">
<xsl:attribute name="xml:id">
<xsl:value-of select="$bibl/@xml:id"/>
</xsl:attribute>
</xsl:when>
</xsl:choose>
</xsl:for-each>
<xsl:apply-templates select="node()"/>
</ref>
</xsl:template>
</xsl:stylesheet>
当应用于您的示例XML时,输出以下内容
<text>
<ref xml:id="1">Author1, Title1, Date1</ref>
<ref>Author75, Title75, Date2</ref>
<ref xml:id="2">Author2, Title2, Date2</ref>
<ref xml:id="3">Author3, Title3, Date3</ref>
</text>
但是,您当前的方法效率不高,因为每个 ref 元素都会迭代所有 bibl 元素。另一种方法是从 ref 元素中提取作者和日期,然后直接查找 bibl 元素
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ref">
<xsl:variable name="author" select="normalize-space(substring-before(., ','))"/>
<xsl:variable name="date" select="normalize-space(substring-after(substring-after(., ','), ','))"/>
<ref>
<xsl:apply-templates select="@* "/>
<xsl:apply-templates select="document('list.xml')//bibl[author=$author][date=$date]"/>
<xsl:apply-templates select="node()"/>
</ref>
</xsl:template>
<xsl:template match="bibl">
<xsl:attribute name="xml:id">
<xsl:value-of select="@xml:id"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
这也应该给出相同的结果。