使用defaultnamespace的XML文件上的XSLT。 Xave与' artificial'字首

时间:2014-06-01 20:51:07

标签: xml xslt xpath

我有一个带有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>

3 个答案:

答案 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>

由于源中的命名空间是默认命名空间,因此该命名空间适用于所有后代元素,不仅适用于bookstorebook。在样式表中,您将该命名空间分配给前缀,因为XPath 需要命名空间中的任何元素选择器都显式前缀。

答案 2 :(得分:1)

如果命名空间对您的转换不是那么重要 更改模板:

<xsl:template match="book">

为:

<xsl:template match="*[local-name(.)=‘book']">

无论命名空间如何,都可以使模板正常工作。如果你需要使用它来处理简单的转换可能对你有用。