【问题标题】:How to get right values from second XML file?如何从第二个 XML 文件中获取正确的值?
【发布时间】:2019-10-26 05:20:19
【问题描述】:

我正在尝试获取两个单独的 XML 文件,并使用 XSL 将它们变成一个 HTML 文件。我从第一个 XML 中得到了正确的东西,但是当我从第二个 XML 中尝试相同的内容时,我要么在一行中得到所有单词,要么只得到第一个单词几次。

XML 1

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="xsltcss.css"?>
<?xml-stylesheet type="text/xsl" href="xslt.xsl" ?>    
<lexicon>
    <head>
        <title>Danish</title>
        <author>Mattias Liljegren</author>
    </head>
    <language value="danish">
        <word value="dog">hund</word>
        <word value="coffee">kaffe</word>
        <word value="tree">træ</word>
        <word value="chair">stol</word>
        <word value="flashlight">lommelygte</word>
        <word value="cat">kat</word>
        <word value="fish">fisk</word>
        <word value="car">bil</word>
        <word value="phone">telefon</word>
        <word value="forest">skov</word>
    </language>
</lexicon>

XML 2

<?xml version="1.0" encoding="UTF-8"?>    
<lexicon>
    <head>
        <title>Croatian</title>
        <author>Mattias Liljegren</author>
    </head>
    <language value="croatian">
        <word value="dog">pas</word>
        <word value="coffee">kava</word>
        <word value="tree">drvo</word>
        <word value="chair">stolica</word>
        <word value="flashlight">baterija</word>
        <word value="cat">mačka</word>
        <word value="fish">riba</word>
        <word value="car">automobil</word>
        <word value="phone">telefon</word>
        <word value="forest">šuma</word>
    </language>
</lexicon>

XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes" />
   <xsl:template match="/">
      <html>
         <head>
            <link rel="stylesheet" type="text/css" href="xsltcss.css" />
         </head>
         <body>
            <xsl:for-each select="lexicon/head/title">
               <p>
                  <xsl:value-of select="." />
               </p>
               <p>
                  <xsl:value-of select="document('kroatiska.xml')/lexicon/head/title/." />
               </p>
            </xsl:for-each>
            <xsl:for-each select="lexicon/language/word">
               <p>
                  <xsl:value-of select="." />
               </p>
            </xsl:for-each>
            <xsl:for-each select="lexicon/language/word">
               <p>
                  <xsl:value-of select="document('kroatiska.xml')/lexicon/language/word" />
               </p>
            </xsl:for-each>
         </body>
      </html>
   </xsl:template>
</xsl:stylesheet>

两个单独的 xml 文件,我想要每个文件的第一个单词,然后是第二个单词,依此类推。 Atm 我从原始 xml 中得到正确的,但只有第二个 xml 文件中的第一个单词“pas”。

预期结果:

Danish
hund
kaffe 
trä  
stol  
lommelygte 
kat
fisk
bil
telefon 
skov
Croatian
pas 
kava
drvo
stolica
baterija
macka
riba
automobil
telefon
suma

【问题讨论】:

  • 转换的预期结果是什么?
  • 另外,您真的在使用 XSLT 2.0 处理器吗?您的样式表显示 version="2.0" 但此 &lt;?xml-stylesheet type="text/xsl" href="xslt.xsl" ?&gt; 表明您正在浏览器中进行转换,即 XSLT 1.0。
  • Atm 我将顶部单词作为单独的行,底部单词作为相同数量的行但只有第一个单词 pas,或者当我多次将所有单词放在一行中尝试编辑代码。我希望它从每个 xml 中获取第一个单词,然后从每个 xml 中获取第二个单词,依此类推。我不知道我正在使用哪个处理器,为学校做这个,所以我有点迷路:)
  • 恐怕这会令人困惑。请编辑您的问题并添加您期望从给定示例中获得的确切结果。 -- 如果您不知道您使用的是哪个处理器,请查找:stackoverflow.com/questions/25244370/…
  • 我现在已经更新了底部,所以我希望它不会那么混乱。我正在使用版本 1!将它从 2.0 编辑到 1,谢谢!

标签: xml xslt


【解决方案1】:

我认为您可能希望将这两个列表并排放置,就像在字典中一样。要获得两个单独列表的显示结果相当简单:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>

<xsl:template match="/lexicon">
    <html>
        <body>
            <!-- this document -->
            <h3>
                <xsl:value-of select="language/@value"/>
            </h3>
            <xsl:for-each select="language/word">
                <p>
                    <xsl:value-of select="."/>
                </p>
            </xsl:for-each>
            <!-- external document -->
            <xsl:variable name="kroatiska" select="document('kroatiska.xml')/lexicon" />
            <h3>
                <xsl:value-of select="$kroatiska/language/@value"/>
            </h3>
            <xsl:for-each select="$kroatiska//language/word">
                <p>
                    <xsl:value-of select="."/>
                </p>
            </xsl:for-each>
        </body>
    </html>
</xsl:template>

</xsl:stylesheet>

【讨论】:

    【解决方案2】:

    根据引人入胜的 XSLT 讨论 For loops vs. apply-templates,考虑使用替代版本来避免许多 &lt;xsl:for-each&gt; 调用。根据 XSLT 专家的建议(@Tomalak@DimitreNovatchev@MichaelKay):

    • 使用for-each 会使您的程序更加复杂: 添加嵌套级别并且重用代码也是不可能的 在 for-each 块内。使用apply-templates 将(完成后 对)生成更灵活和模块化的 XSLT。

    • 使用&lt;xsl:template&gt;&lt;xsl:apply-templates&gt;更强大更优雅...xsl:apply-templatesxsl:for-each更丰富更深入,甚至只是因为我们不知道将在节点上应用什么代码选择——在一般情况下,对于节点列表的不同节点,此代码会有所不同。

    • xsl:apply-templates 相对于for-each 的主要优势在于代码能够更好地适应不断变化的文档结构和不断变化的处理要求。


    在您的情况下,由于您需要遍历外部文档中的节点,xsl:for-each 是不可避免的:

    XSLT (使用lexiconlanguageword 模板)

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
       <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes" />
    
       <xsl:template match="/lexicon">
            <html>
                <head>
                    <link rel="stylesheet" type="text/css" href="xsltcss.css" />
                </head>
                <xsl:apply-templates select="language" />
            </html>
       </xsl:template>   
    
       <xsl:template match="language">
            <body>
                <xsl:variable name="other_doc" select="document('kroatiska.xml')" />
                <h3>
                   <xsl:value-of select="@value"/>
                </h3>
                <xsl:apply-templates select="word" />
                <h3>
                    <xsl:value-of select="$other_doc/lexicon/language/@value" />
                </h3>
                <xsl:for-each select="$other_doc/lexicon/language/word">
                    <p>
                      <xsl:value-of select="text()" />
                    </p>
                </xsl:for-each>
            </body>
       </xsl:template>   
    
       <xsl:template match="word">
            <p>
              <xsl:value-of select="text()" />
            </p>
       </xsl:template>   
    
    </xsl:stylesheet>
    

    HTML

    <html>
      <head>
        <META http-equiv="Content-Type" content="text/html; charset=utf-8">
        <link rel="stylesheet" type="text/css" href="xsltcss.css">
      </head>
      <body>
        <h3>danish</h3>
        <p>hund</p>
        <p>kaffe</p>
        <p>træ</p>
        <p>stol</p>
        <p>lommelygte</p>
        <p>kat</p>
        <p>fisk</p>
        <p>bil</p>
        <p>telefon</p>
        <p>skov</p>
        <h3>croatian</h3>
        <p>pas</p>
        <p>kava</p>
        <p>drvo</p>
        <p>stolica</p>
        <p>baterija</p>
        <p>mačka</p>
        <p>riba</p>
        <p>automobil</p>
        <p>telefon</p>
        <p>šuma</p>
      </body>
    </html>
    

    【讨论】:

    • 为什么你认为“既然你需要遍历外部文档中的节点,xsl:for-each,是不可避免的”? --附言我相信在这种情况下使用xsl:for-each 是一个更好的选择:它使代码更短且更具可读性。恕我直言,您的版本患有 GOTO 综合症。
    • 如果你能通过document()展示如何避免节点上的xsl:for-each,我很感兴趣!也许在 2.0 中?此外,OP 可能与其他节点有一个更大的 XML,并且只在此处发布了一个 sn-p。另外,将来,XSLT 新手读者可能会认为来自 root 的多个 for-each 是唯一的方法。同样,这是一种替代方法,希望引用一般的最佳实践。
    • 我已经发布了另一个答案表明这一点。 ——没有“一般的最佳实践”。每个案例都需要自己权衡。
    【解决方案3】:

    这是根据 Parfait 的回答对 cme​​ts 的扩展。

    Parfait 在他的回答中说:

    在您的情况下,由于您需要遍历外部文档中的节点,xsl:for-each 是不可避免的:

    在评论中我问为什么会这样,Parfait 回答:

    如果您可以通过document() 展示如何避免节点上的xsl:for-each,我非常感兴趣!

    以下样式表展示了如何仅使用 apply-templates 获得相同的结果:

    XSLT 1.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html"/>
    
    <xsl:template match="/lexicon">
        <html>
            <body>
                <xsl:apply-templates select="language | document('kroatiska.xml')/lexicon/language" />
            </body>
        </html>
    </xsl:template>
    
    <xsl:template match="language">
        <h3>
            <xsl:value-of select="@value"/>
        </h3>
        <xsl:apply-templates/>
    </xsl:template>
    
    <xsl:template match="word">
        <p>
            <xsl:value-of select="."/>
        </p>
    </xsl:template>
    
    </xsl:stylesheet>
    

    这并不意味着在这种情况下使用xsl:apply-templatesxsl:for-each 更好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-19
      • 1970-01-01
      • 2021-10-16
      • 1970-01-01
      相关资源
      最近更新 更多