首页 > 解决方案 > XML - XSLT - 使用两个 XML 输入文档

问题描述

我有一个小问题,可能很容易解决,但我整个下午都在处理它,我真的不知道如何解决它,

基本上,我有以下输入 XML 文档:

<?xml version="1.0" encoding="UTF-8"?>
<parent>
    <childs>
        <child ID="1" name="John" />
        <child ID="2" name="Marie"/>
        <child ID="3" name="Joseph"/>
    </childs>
</parent> 

我想向<child>它添加另一个元素,但我想从一个名为“inputStack.xml”的外部文件中获取孩子的名字,这个:

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design">
    <property name="units">in</property>
    <text-property name="displayName">Daisy</text-property>
    <text-property name="text">Just plain text</text-property>
</report>

基本上我想添加一个<child>名为 Daisy 的新元素

所以这是我想要得到的输出 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<parent>
    <childs>
        <child ID="1" name="John"/>
        <child ID="2" name="Marie"/>
        <child ID="3" name="Joseph"/>
        <child ID="4" name="Daisy"/>
    </childs>
</parent>

这是我正在使用的 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs"
  expand-text="yes"
  version="3.0">

    <xsl:output indent="yes" />

    <xsl:mode on-no-match="shallow-copy"/>

    <xsl:template match="parent/childs/child[last()]">

    <xsl:next-match/>
        <child>
            <xsl:attribute name="ID">
                <xsl:value-of select="count(preceding-sibling::child)+2" />
            </xsl:attribute>
            <xsl:attribute name="name">
                <xsl:value-of select="document('inputStack.xml')/report/text-property[@name = 'displayName']"/>
            </xsl:attribute>

        </child>
    </xsl:template>

</xsl:stylesheet>

我得到的输出是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<parent>
    <childs>
        <child ID="1" name="John"/>
        <child ID="2" name="Marie"/>
        <child ID="3" name="Joseph"/>
        <child ID="4" name=""/>
    </childs>
</parent>

如您所见,我无法在属性值等于...的text-property元素中获取值namedisplayName

现在这就是我的问题所在:如您所见,我正在使用的外部文件/文档xmlns具有 value 属性http://www.eclipse.org/birt/2005/design。我发现如果我取出这个属性,XSLT 代码就会起作用,并且值Daisy会添加到生成的 XML 文档中。但问题是我无法从外部 XML 文件中取出该属性,那么如何为该外部文档定义名称空间以使其正常工作?还是有其他方法可以做到这一点?

谢谢!

编辑/更新

我正在尝试在document()函数内部使用该函数,count()但我不知道为什么它不起作用......所以我正在使用的外部文件已经更新:

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design">
    <property name="units">in</property>
    <text-property name="displayName">Daisy</text-property>
    <text-property name="text">Just plain text</text-property>
    <propList>
        <prop name="prop1"/>
        <prop name="prop2"/>
        <prop name="prop3"/>
        <prop name="prop4"/>
        <prop name="prop5"/>
    </propList>
</report>

这是我的 XSLT 更新:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:ecd="http://www.eclipse.org/birt/2005/design"
  exclude-result-prefixes="xs ecd"
  expand-text="yes"
  version="3.0">

    <xsl:output indent="yes" />

    <xsl:mode on-no-match="shallow-copy"/>

    <xsl:template match="parent/childs/child[last()]">

    <xsl:next-match/>
        <child>
            <xsl:attribute name="ID">
                <xsl:value-of select="count(preceding-sibling::child)+2" />
            </xsl:attribute>
            <xsl:attribute name="name">
                <xsl:value-of select="document('inputStack.xml')/ecd:report/ecd:text-property[@name = 'displayName']"/>
            </xsl:attribute>
            <!--new attribute-->
            <xsl:attribute name="nProps">
                <xsl:value-of select="count(document('inputStack.xml')/ecd:report/ecd:propList/(preceding-sibling::ecd:prop[last()]))+1"/>
            </xsl:attribute>
        </child>
    </xsl:template>

</xsl:stylesheet>

这是我得到的结果:

<?xml version="1.0" encoding="UTF-8"?>
<parent>
    <childs>
        <child ID="1" name="John"/>
        <child ID="2" name="Marie"/>
        <child ID="3" name="Joseph"/>
      <child ID="4" name="Daisy" nProps="1"/>
    </childs>
</parent>

所以nProps值应该是 5 而不是 1……我在路上做错了吗?谢谢

亚历山大·哈辛托

标签: xmlxsltxslt-3.0

解决方案


对于那条指令,您可以使用

<xsl:value-of xpath-default-namespace="http://www.eclipse.org/birt/2005/design" select="document('inputStack.xml')/report/text-property[@name = 'displayName']"/>

https://www.w3.org/TR/xslt-30/#unprefixed-qnames。如果您有更多需要使用命名空间的 XSLT 元素,您可以xpath-default-namespace在一个公共容器元素上声明,但请记住,您希望使用具有不同命名空间的两个文档,因此您需要确保需要默认命名空间的元素命名空间为空,您不会覆盖它。

根据您的需要,在样式表中为命名空间声明前缀<xsl:stylesheet xmlns:ecd="http://www.eclipse.org/birt/2005/design" ...>并使用该前缀可能更容易,然后在需要限定document('inputStack.xml')/ecd:report/ecd:text-property[@name = 'displayName']XPath 表达式中的元素名称时使用该前缀。


推荐阅读