【问题标题】:Cross-referencing with AND condition in XSLT在 XSLT 中使用 AND 条件进行交叉引用
【发布时间】:2019-05-22 11:50:35
【问题描述】:

我正在尝试从外部 XML 文件交叉引用,但不是只比较一个键,而是询问是否存在一个字符串和其他字符串,以及是否存在来自外部文件的引用:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="http://www.tei- 
c.org/ns/1.0"
xmlns="http://www.tei-c.org/ns/1.0" exclude-result-prefixes="xs t">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="ids"
    select="document('instructions.xml')"/>

<xsl:key name="id" match="row" use="tokenize(normalize-space(elem[@name='Instruction']), ' ')"/>


<!-- identity transform -->
<xsl:template match="@* | node() | text() | *">
    <xsl:copy>
        <xsl:apply-templates select="@* | node() | text() | *"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="instruction">
    <xsl:for-each select=".[contains(.,key('id', ., .))]">
    <xsl:copy>     
        <xsl:attribute name="norm">
            <xsl:value-of select="normalize-space(key('id', normalize-space(.), $ids)/elem[@name='Norm'])"/>
        </xsl:attribute>
        <xsl:apply-templates select="@* | node() | text() | *"/>   
    </xsl:copy>
    </xsl:for-each>
</xsl:template>

输入(外部文件):

<row>
  <elem name="instruction">pour out</elem>
  <elem name="norm">p1</elem>
</row>

输入(要注释的文件):

<ab type="recipe">
Bla bla
  <instruction>pour the milk out</instruction> bla
</ab>

期望的输出:

<ab type="recipe">
Bla bla
  <instruction norm="p1">pour the milk out</instruction> bla
</ab>

换句话说:外部 XML 文件中元素 &lt;elem name="instruction"&gt;“pour”和“out”中的两个标记都需要包含在我的 XML 文件中的 &lt;instruction&gt;元素中。如果是,我想在外部文件中将 norm 属性设置为 &lt;elem name="norm"&gt; 的值。

非常感谢任何帮助!

【问题讨论】:

  • 由于elem name="instruction" 元素包含您标记的单词列表,instruction 元素中单词的顺序是否重要,即它是否必须以相同的顺序包含单词(@ 987654330@, out)?
  • 没有顺序根本不重要! “out blabla pour”也应该匹配。但是,我有这样的情况,我可以在输入数据中用另一个规范值“倒”。 "pour out --> p1", "pour --> p0" ..如果它实际上包含所有单词,它应该首先匹配。所以在这种情况下p1。如果是“倒牛奶”,应该是 p0。

标签: xslt xslt-2.0 cross-reference


【解决方案1】:

我不知道如何用钥匙来做,但我确实想出了另一种方法....

<xsl:template match="instruction">
    <xsl:variable name="words" select="tokenize(normalize-space(.), ' ')" />
    <xsl:variable name="row" select="$ids//row[every $i in tokenize(normalize-space(elem[@name='instruction']), ' ') satisfies $i = $words]" />
    <xsl:copy>
        <xsl:if test="$row">
            <xsl:attribute name="norm" select="$row/elem[@name='norm']" />    
        </xsl:if>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

编辑:针对您的评论,如果您可以匹配多行,那么要获得匹配词最多的行,请执行此操作....

<xsl:template match="instruction">
    <xsl:variable name="words" select="tokenize(normalize-space(.), ' ')" />
    <xsl:variable name="row" as="element()*">
        <xsl:perform-sort select="$ids//row[every $i in tokenize(normalize-space(elem[@name='instruction']), ' ') satisfies $i = $words]">
            <xsl:sort select="count(tokenize(normalize-space(elem[@name='instruction']), ' '))" order="descending" />
        </xsl:perform-sort>
    </xsl:variable>
    <xsl:copy>
        <xsl:if test="$row">
            <xsl:attribute name="norm" select="$row[1]/elem[@name='norm']" />    
        </xsl:if>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

【讨论】:

  • 这是一个非常好的方法!我只是想问一下您是否也知道如何处理输入数据中重复出现的相同单词之一和另一个“规范”的情况:&lt;row&gt; &lt;elem name="instruction"&gt;pour out&lt;/elem&gt; &lt;elem name="norm"&gt;p1&lt;/elem&gt; &lt;/row&gt; &lt;row&gt; &lt;elem name="instruction"&gt;pour&lt;/elem&gt; &lt;elem name="norm"&gt;p0&lt;/elem&gt; &lt;/row&gt; 使用您的解决方案,我现在得到&lt;instruction norm="p0 p1"&gt;
  • 你想只输出第一个,还是输出最多的行?
  • 最匹配单词的行在前。如果句子是“po​​ur the milk”,那么它实际上应该是 p0。但“倒牛奶”应该是 p1。
  • 非常感谢!
  • 顺便说一句,node() 实际上是* | text() | comment() | processing-instruction() 的简写,所以node() | text() | * 无论如何都可以缩短为node()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多