我有这样的代码
<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>
答案 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,'
')"/>
<xsl:value-of select="concat('Author Name: ',
/*/Authors/Author[@path=current()/Author-Ref]/Name,'
')"/>
</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
搜索Name
和Author-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>
</xsl:text>
<xsl:text>Auther Name: </xsl:text>
<xsl:value-of select="dyn:evaluate(Author-Ref)/Name"/>
<xsl:text>
</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"/>