XML - XSLT - 使用两个 XML 输入文档
XML - XSLT - Using two XML input documents
我有一个小问题,可能很容易解决,但我已经花了一个下午,我真的不知道如何解决,
基本上,我有以下输入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' 的外部文件中获取 child 的名称,这个:
<?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>
基本上我想添加一个名为 Daisy
的新 <child>
元素
所以这是我想要得到的输出 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>
如您所见,我无法获得属性 name
值等于 displayName
...[=31= 的 text-property
元素中的值]
现在这就是我的问题所在:如您所见,我正在使用的外部 file/document 有一个值为 http://www.eclipse.org/birt/2005/design
的 xmlns
属性。我发现,如果我去掉这个属性,XSLT 代码就可以工作,并且值 Daisy
被添加到生成的 XML 文档中。但问题是我无法从外部 XML 文件中取出该属性,那么我如何为该外部文档定义一个命名空间以使其工作?或者还有其他方法吗?
谢谢!
EDIT/UPDATE
我正在尝试在 count()
函数中使用 document()
函数,但我不知道为什么它不起作用...所以我正在使用的外部文件已更新:
<?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...我在路径中做错了什么吗?谢谢
亚历山大·哈辛托
对于那条指令,您可以使用
<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 表达式中可能会更容易.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs mn" xmlns:mn="http://www.eclipse.org/birt/2005/design"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="doc" select="document('date3.xml')"/>
<xsl:template match="parent">
<xsl:copy>
<childs>
<xsl:for-each select="childs/child">
<child>
<xsl:attribute name="ID">
<xsl:value-of select="@ID"/>
</xsl:attribute>
<xsl:attribute name="name">
<xsl:value-of select="@name"/>
</xsl:attribute>
</child>
</xsl:for-each>
<child>
<xsl:attribute name="ID">
<xsl:value-of select="'4'"/>
</xsl:attribute>
<xsl:attribute name="name">
<xsl:value-of select="$doc/mn:report/mn:text-property[@name='displayName']"/>
</xsl:attribute>
</child>
</childs>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我有一个小问题,可能很容易解决,但我已经花了一个下午,我真的不知道如何解决,
基本上,我有以下输入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' 的外部文件中获取 child 的名称,这个:
<?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>
基本上我想添加一个名为 Daisy
的新<child>
元素
所以这是我想要得到的输出 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>
如您所见,我无法获得属性 name
值等于 displayName
...[=31= 的 text-property
元素中的值]
现在这就是我的问题所在:如您所见,我正在使用的外部 file/document 有一个值为 http://www.eclipse.org/birt/2005/design
的 xmlns
属性。我发现,如果我去掉这个属性,XSLT 代码就可以工作,并且值 Daisy
被添加到生成的 XML 文档中。但问题是我无法从外部 XML 文件中取出该属性,那么我如何为该外部文档定义一个命名空间以使其工作?或者还有其他方法吗?
谢谢!
EDIT/UPDATE
我正在尝试在 count()
函数中使用 document()
函数,但我不知道为什么它不起作用...所以我正在使用的外部文件已更新:
<?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...我在路径中做错了什么吗?谢谢
亚历山大·哈辛托
对于那条指令,您可以使用
<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 表达式中可能会更容易.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs mn" xmlns:mn="http://www.eclipse.org/birt/2005/design"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="doc" select="document('date3.xml')"/>
<xsl:template match="parent">
<xsl:copy>
<childs>
<xsl:for-each select="childs/child">
<child>
<xsl:attribute name="ID">
<xsl:value-of select="@ID"/>
</xsl:attribute>
<xsl:attribute name="name">
<xsl:value-of select="@name"/>
</xsl:attribute>
</child>
</xsl:for-each>
<child>
<xsl:attribute name="ID">
<xsl:value-of select="'4'"/>
</xsl:attribute>
<xsl:attribute name="name">
<xsl:value-of select="$doc/mn:report/mn:text-property[@name='displayName']"/>
</xsl:attribute>
</child>
</childs>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>