如何使用外部xml数据使用xslt自动编码文本

时间:2013-10-08 23:35:28

标签: xml xslt

我有一个简单的xml文本和一个小人物。我想找到所有人'在文中提到并使用人物学中的信息标记它们。 我的文字看起来像这样:

<text>
    <div>
        <p>Mohandas Ghandi was an Indian lawyer, born in 1869.</p>
        <p>Albert Einstein was a German physicist, born in 1879.</p>
        <p>Helen Keller was an American author, born in 1880.</p>
        <p>Joan Baez is an American singer/songwriter, born in 1941.</p>
    </div>
</text>

我的人物外观如下:

<people>
    <person id="ghandi">
        <name>Mohandas Ghandi</name>
        <birthPlace>Porbandar, India</birthPlace>
    </person>
    <person id="einstein">
        <name>Albert Einstein</name>
        <birthPlace>Ulm, Germany</birthPlace>
    </person>
    <person id="keller">
        <name>Helen Keller</name>
        <birthPlace>Tuscumbia, USA</birthPlace>
    </person>
</people>

到目前为止,我有这个xslt(2.0):

<xsl:variable name="personography" select="doc('people.xml')"/>   
<xsl:variable name="pName" select="$personography//person[1]/name"/>
<xsl:variable name="pId" select="$personography//person[1]/@id"/>

<xsl:template match="*">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>    

<xsl:template name="encNames" match="text()">
    <xsl:analyze-string select="."  regex="{$pName}">
        <xsl:matching-substring>
            <persName corresp="{concat('people.xml#',$pId)}">
                <xsl:value-of select="."/>
            </persName>
        </xsl:matching-substring>
        <xsl:non-matching-substring>
            <xsl:copy-of select="."/>
        </xsl:non-matching-substring>
    </xsl:analyze-string>
</xsl:template>

我得到了回复:

<text>
    <div>
        <p><persName corresp="people.xml#ghandi">Mohandas Ghandi</persName> was an Indian lawyer, born in 1869.</p>
        <p>Albert Einstein was a German physicist, born in 1879.</p>
        <p>Helen Keller was an American author, born in 1880.</p>
        <p>Joan Baez is an American singer/songwriter, born in 1941.</p>
    </div>
</text>

所以,我的问题是,如何在我的文本中标记其余的人?我假设它需要一个使用跟随兄弟的功能,但我还没有比这更进一步。我错过了什么?我至少走在正确的轨道上吗? 感谢。

2 个答案:

答案 0 :(得分:1)

我要做的是更改pName以返回一系列名称而不是第一个人的名字。然后,我将使用该序列构建一个新的正则表达式。

示例...

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:preserve-space elements="p"/>

    <xsl:variable name="personography" select="doc('people.xml')"/>
    <xsl:variable name="pName" select="$personography/*/person/name"/>

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

    <xsl:template match="text()" priority="1">
        <xsl:analyze-string select="."  regex="({string-join($pName,'|')})">
            <xsl:matching-substring>
                <persName corresp="{concat('people.xml#',$personography/*/person[name=current()]/@id)}">
                    <xsl:value-of select="."/>
                </persName>
            </xsl:matching-substring>
            <xsl:non-matching-substring>
                <xsl:copy-of select="."/>
            </xsl:non-matching-substring>
        </xsl:analyze-string>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:0)

它有点冗长,可能会被优化或重构,但有效。

此模板将遍历每个人并应用analyze-string。结果位于名为$person-matches的变量中,每个人都有一个<match>

如果匹配的内容包含<persName>,请使用该匹配项。否则,请使用模板中匹配的原始文本。

<xsl:template match="text()">
    <xsl:variable name="txt" select="."/>

    <xsl:variable name="person-matches">
      <xsl:for-each select="$personography/person">
        <xsl:variable name="person" select="."/>
          <match>
            <xsl:analyze-string select="$txt"  regex="({$person/name})">
                <xsl:matching-substring>
                    <persName corresp="{concat('people.xml#',$person/@id)}">
                        <xsl:value-of select="regex-group(1)"/>
                    </persName>
                </xsl:matching-substring>
                <xsl:non-matching-substring>
                    <xsl:value-of select="."/>
                </xsl:non-matching-substring>
            </xsl:analyze-string>
          </match>
        </xsl:for-each>
    </xsl:variable>

    <xsl:choose>
        <xsl:when test="$person-matches/match[persName]">
            <xsl:sequence select="$person-matches/match[persName]/node()"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="."/>
        </xsl:otherwise>
    </xsl:choose>

</xsl:template>