【问题标题】:How do I supply attribute values from another XML document using XSLT?如何使用 XSLT 从另一个 XML 文档提供属性值?
【发布时间】:2019-05-09 13:52:09
【问题描述】:

我有两个 XML 文档。一个(我们称之为 xml1)列出了一系列“w”元素,每个元素都有一个“orig”属性。另一个文档 (xml2) 列出了一系列相关的 'w' 元素,但具有不同的属性 ('norm')。我想合并这两个文档,这样我就只有一系列具有所有属性('orig' 和 'norm')的元素。

这听起来很简单,但我无法让代码正常工作,我无法让代码选择属性“norm”的单个值,而不是所有可用值。

我尝试使用命令从 xml2 中选择属性值

<xsl:value-of select="document('xml2.xml')//@norm"/>

但这所做的只是选择 xml2 中所有“规范”属性的值。

我还尝试为两个文档中的每个元素赋予一个唯一的 xml:id 属性,以便它们可以匹配,但是任何时候我使用条件语句来匹配它们,我都会得到相同的结果。

如果我使用“for each”命令,则不会选择任何元素。

这里是 xml1 的示例:

    <text>
        <seg type="stanza" n="1">
            <l n="1">
                <w xml:id="1" orig="Haile"/>
                <w xml:id="2" orig=","/>
                <w xml:id="3" orig="sterne"/>
                <w xml:id="4" orig="superne"/>
                <w xml:id="5" orig="!"/>
            </l>
        </seg>
    </text>

这里是 xml2 的示例:

    <text>
        <seg type="stanza" n="1">
            <l n="1">
                <w xml:id="1" norm="Hail"/>
                <w xml:id="2" norm=","/>
                <w xml:id="3" norm="star"/>
                <w xml:id="4" norm="supernal"/>
                <w xml:id="5" norm="!"/>
            </l>
        </seg>
    </text>

我想制作这个:

    <text>
        <seg type="stanza" n="1">
            <l n="1">
                <w xml:id="1" orig="Haile" norm="Hail"/>
                <w xml:id="2" orig="," norm=","/>
                <w xml:id="3" orig="sterne" norm="star"/>
                <w xml:id="4" orig="superne" norm="supernal"/>
                <w xml:id="5" orig="!" norm="!"/>
            </l>
        </seg>
    </text>

到目前为止,我的 xslt 文件如下所示:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"    
    xpath-default-namespace="http://www.tei-c.org/ns/1.0"
    xmlns="http://www.tei-c.org/ns/1.0"
    version="2.0">

    <xsl:output method="xml" indent="no"/>

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

    <!-- combine attributes from separate files -->
    <xsl:template match="//w">
        <xsl:copy>
             <xsl:apply-templates select="@*"/>
                  <xsl:attribute name="norm">
                       <xsl:value-of select="document('xml2.xml')//@norm"/>
                  </xsl:attribute>
        </xsl:copy>        
    </xsl:template>

</xsl:stylesheet>

如果可以的话,请帮帮我。谢谢。

【问题讨论】:

    标签: xml xslt xpath


    【解决方案1】:

    最好使用 key 处理查找。尝试(未经测试):

    XSLT 2.0

    <xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:key name="norm" match="w" use="@xml:id" />
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="w">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:copy-of select="key('norm', @xml:id, document('xml2.xml'))/@norm"/>   
        </xsl:copy>        
    </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 您不需要密钥,id 函数在 XSLT 2 中就足够了,并且具有 xml:id 属性。
    • @MartinHonnen 似乎还不够:xsltfiddle.liberty-development.net/gWvjQfF
    • 看来xml:id 属性值必须是有效的xs:ID 值才能使撒克逊支持id 函数(xsltfiddle.liberty-development.net/gWvjQfF/1),我目前不确定这是有意还是必需是否按规格。 XQuery 中的 BaseX 似乎可以与 idxml:id="1" 一起正常工作,XmlPrime 拒绝具有此类 ID 的输入 XML。不确定使用的 TEI 文档格式是否真的使用这样的数字 id 值,但如果值是数字,则使用键似乎更安全。
    • 谢谢你——这对我有用。谢谢大家的建议和帮助!
    【解决方案2】:
    <xsl:output method="xml" indent="yes"/>
        <xsl:variable name="imp" select="document('Stanza1.xml')"/>
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="l">
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:for-each select="w">
                    <xsl:copy>
                    <xsl:copy-of select="@*"/>
                    <xsl:copy-of select="$imp/text/seg/l/w[@xml:id = current()/@xml:id]/@norm"/>
                    </xsl:copy>
                </xsl:for-each>
            </xsl:copy>
        </xsl:template>
    You may use like this
    

    【讨论】:

      猜你喜欢
      • 2018-12-27
      • 1970-01-01
      • 1970-01-01
      • 2021-03-26
      • 1970-01-01
      • 1970-01-01
      • 2017-05-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多