我有一个带有defaultnamespace的大型数据库XML文件,可以使用XSLT进行转换。这是一个最小的例子。
该文件名为server.xml。它包含不正确的数据。
<?xml version="1.0" encoding="UTF-8"?>
<bookstore xmlns="http://www.mybook.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<book author="Incorrect_Author">
<title>Correct_Title</title>
</book>
</bookstore>
需要通过在另一个XML文件中匹配书名来将作者更改为正确的值。
第二个xml文件名为client.xml。它包含该书的正确作者姓名。
<?xml version="1.0" encoding="UTF-8"?>
<bookstore xmlns="http://www.mybook.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<book author="Correct_Author">
<title>Correct_Title</title>
<additionalstuff/>
</book>
</bookstore>
然而,它还有我不想要的其他信息。所以我想根据客户端修改服务器,按书名进行匹配。
我编写了以下XSLT(基于this answer)。如果我人工删除xml文件中的默认xmlns,它可以完成这项工作。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="clientXml" select="'client.xml'" />
<xsl:variable name="client" select="document($clientXml)//book" />
<xsl:template match="book/@author">
<xsl:attribute name="author">
<xsl:value-of select="$client[child::title=current()/../title]/@author" />
</xsl:attribute>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
但是,我需要这样来处理文件(包含默认的ns)。我知道这是一个当前的问题,所以我根据我找到的答案尝试了以下代码。它不起作用。这是XPath前缀的问题吗?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:v="http://www.mybook.com" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="v" >
<xsl:output method="xml" indent="yes"/>
<xsl:param name="clientXml" select="'client.xml'" />
<xsl:variable name="client" select="document($clientXml)//v:book" />
<xsl:template match="v:book/@author">
<xsl:attribute name="author">
<xsl:value-of select="$client[child::title=current()/../title]/@author" />
</xsl:attribute>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:1)
XPath,包括在XSLT中使用的那些,是名称空间感知的...并且遗憾的是不支持默认名称空间的概念,至少在1.0版本的规范中。要匹配命名空间节点,即使您未在输入文档中执行此操作,也必须在样式表的路径中使用正确绑定的前缀。
答案 1 :(得分:1)
你快到了。前缀是正确的方法。您刚刚错过了title
元素选择器的前缀:
<xsl:template match="v:book/@author">
<xsl:attribute name="status">
<xsl:value-of select="$client[child::v:title=current()/../v:title]/@author" />
</xsl:attribute>
</xsl:template>
由于源中的命名空间是默认命名空间,因此该命名空间适用于所有后代元素,不仅适用于bookstore
或book
。在样式表中,您将该命名空间分配给前缀,因为XPath 需要命名空间中的任何元素选择器都显式前缀。
答案 2 :(得分:1)
如果命名空间对您的转换不是那么重要 更改模板:
<xsl:template match="book">
为:
<xsl:template match="*[local-name(.)=‘book']">
无论命名空间如何,都可以使模板正常工作。如果你需要使用它来处理简单的转换可能对你有用。