如何解析XSLT中的引用

时间:2013-07-11 18:19:36

标签: xml xslt xpath

我有这样的代码

<Library>
    <Books>
        <Book>
            <ISBN>123</ISBN>
            <Name>Book 1</Name>
            <Author-Ref>/Library/Authors/Author[2]</Author-Ref>
        </Book>
        <Book>
            <ISBN>425</ISBN>
            <Name>Book 2</Name>
            <Author-Ref>/Library/Authors/Author[1]</Author-Ref>
        </Book>     
    </Books>
    <Authors>
        <Author>
            <Name>John smith</Name>
            <Nationality>American</Nationality>
            <BirthDate>08051977</BirthDate>
        </Author>
        <Author>
            <Name>Sandra Johns</Name>
            <Nationality>American</Nationality>
            <BirthDate>03091981</BirthDate>
        </Author>       
    </Authors>
</Library>

我想写xslt代码,打印Book Name,Auther Name。

如何使用XSLT解析对Auther名称的引用?

<xsl:for-each select="/Library/Books/Book">
    Book Name: <xsl:value-of select="./Name"/>
    Auther Name: ?????
</xsl:for-each>

3 个答案:

答案 0 :(得分:1)

我会分两个阶段做这件事;第一阶段是添加Author元素的路径。第二阶段使用添加的路径来产生所需的输出。

这可以在单个XSLT(2.0)中完成,方法是将新输入放在变量中添加路径,但这会导致更大文档的内存问题。

XML输入(input.xml)

<Library>
    <Books>
        <Book>
            <ISBN>123</ISBN>
            <Name>Book 1</Name>
            <Author-Ref>/Library/Authors/Author[2]</Author-Ref>
        </Book>
        <Book>
            <ISBN>425</ISBN>
            <Name>Book 2</Name>
            <Author-Ref>/Library/Authors/Author[1]</Author-Ref>
        </Book>     
    </Books>
    <Authors>
        <Author>
            <Name>John smith</Name>
            <Nationality>American</Nationality>
            <BirthDate>08051977</BirthDate>
        </Author>
        <Author>
            <Name>Sandra Johns</Name>
            <Nationality>American</Nationality>
            <BirthDate>03091981</BirthDate>
        </Author>       
    </Authors>
</Library>

第一个XSLT (pass1.xsl)

这会将属性path添加到Author元素。

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

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:if test="self::Author">
                <xsl:attribute name="path">
                    <xsl:for-each select="ancestor-or-self::*">
                        <xsl:value-of select="concat('/',local-name())"/>
                        <xsl:if test="(preceding-sibling::*|following-sibling::*)[local-name()=local-name(current())]">
                            <xsl:value-of select="concat('[',count(preceding-sibling::*[local-name()=local-name(current())])+1,']')"/>                      
                        </xsl:if>
                    </xsl:for-each>
                </xsl:attribute>
            </xsl:if>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

XML输出(temp.xml)

已添加注意@path

<Library>
   <Books>
      <Book>
         <ISBN>123</ISBN>
         <Name>Book 1</Name>
         <Author-Ref>/Library/Authors/Author[2]</Author-Ref>
      </Book>
      <Book>
         <ISBN>425</ISBN>
         <Name>Book 2</Name>
         <Author-Ref>/Library/Authors/Author[1]</Author-Ref>
      </Book>
   </Books>
   <Authors>
      <Author path="/Library/Authors/Author[1]">
         <Name>John smith</Name>
         <Nationality>American</Nationality>
         <BirthDate>08051977</BirthDate>
      </Author>
      <Author path="/Library/Authors/Author[2]">
         <Name>Sandra Johns</Name>
         <Nationality>American</Nationality>
         <BirthDate>03091981</BirthDate>
      </Author>
   </Authors>
</Library>

第二个XSLT (pass2.xsl)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/*/Books/Book">
        <xsl:value-of select="concat('Book Name: ',Name,'&#xA;')"/>
        <xsl:value-of select="concat('Author Name: ',
        /*/Authors/Author[@path=current()/Author-Ref]/Name,'&#xA;')"/>
    </xsl:template>

    <xsl:template match="text()"/>

</xsl:stylesheet>

最终输出

Book Name: Book 1
Author Name: Sandra Johns
Book Name: Book 2
Author Name: John smith

答案 1 :(得分:0)

一种方法是将一些unix shell脚本与xmlstarlet工具混合使用。用于xmlstarlet循环

输入的while命令
xmlstarlet sel -T -t \
    -m "/Library/Books/Book" \
    -v "concat( Name, '>', Author-Ref )" \
    -n \
xmlfile

搜索NameAuthor-Ref内容,并打印以字符>分隔的内容。如果两个字段都包含该字符,则会失败。

Book 1>/Library/Authors/Author[2]
Book 2>/Library/Authors/Author[1]

在循环内打印名称并使用xmlstarlet xpath执行第二个author_ref命令以提取作者姓名。

完整的命令:

while IFS=">" read -r name author_ref; do
    printf "Book name: %s\n" "$name"
    printf "Author Name: %s\n" "$(xmlstarlet sel -T -t -v "${author_ref}/Name" xmlfile)"
done < <(xmlstarlet sel -T -t -m "/Library/Books/Book" -v "concat( Name, '>', Author-Ref )" -n xmlfile)

产量:

Book name: Book 1
Author Name: Sandra Johns
Book name: Book 2
Author Name: John smith

答案 2 :(得分:0)

这是一个XSLT 1.0样式表

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:dyn="http://exslt.org/dynamic"
    extension-element-prefixes="dyn"
    version="1.0">

    <xsl:output method="text"/>

    <xsl:template match="/">
        <xsl:for-each select="/Library/Books/Book">
            <xsl:text>Book Name: </xsl:text>
            <xsl:value-of select="./Name"/>
            <xsl:text>&#x000A;</xsl:text>
            <xsl:text>Auther Name: </xsl:text>
            <xsl:value-of select="dyn:evaluate(Author-Ref)/Name"/>
            <xsl:text>&#x000A;</xsl:text>                
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

使用Xalan和Xsltproc进行测试,使用提供的输入生成此输出:

Book Name: Book 1
Auther Name: Sandra Johns
Book Name: Book 2
Auther Name: John smith

请注意,您需要为处理器提供EXSLT模块。我不是Xalan用户,但根据this回答,还有一个xalan:evaluate。如果您使用的是Saxon,可以使用

进行更新
xmlns:saxon="http://saxon.sf.net/"
extension-element-prefixes="saxon"

<xsl:value-of select="saxon:evaluate(Author-Ref)/Name"/>