问题
I have a little problem that probably is very easy to solve but I've been with it all afternoon and I really don't know how to solve it,
Basically, I have the following input XML document:
<?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>
And I want to add another <child>
element to it, but I want to get the child's name from an external file, called 'inputStack.xml', this one:
<?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>
Basically I want to add a new <child>
element with the name Daisy
So this is the output XML file I want to get:
<?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>
This is the XSLT I'm using:
<?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>
And the output I'm getting is this:
<?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>
As you can see, I'm not being able to get the value in the text-property
element with attribute name
value equal to displayName
...
Now this is where I have my problem: As you can see, the external file/document I'm using has an xmlns
attribute with value http://www.eclipse.org/birt/2005/design
. I discovered that if I take out this attribute, the XSLT code works and the value Daisy
is added to the resulting XML document. But the problem is that I can't take out that attribute from the external XML file, so how can I define a namespace for that external document so that it works? Or is there another way to do this?
Thank you!
EDIT/UPDATE
I am trying to use the document()
function inside the count()
function but I don't know why it is not working... So the external file I'm using has been updated:
<?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>
Here is my XSLT updated:
<?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>
And here is the result I am getting:
<?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>
So nProps
value should be 5 instead of 1... Am I doing anything wrong in the path? Thank you
Alexandre Jacinto
回答1:
For that single instruction you can use
<xsl:value-of xpath-default-namespace="http://www.eclipse.org/birt/2005/design" select="document('inputStack.xml')/report/text-property[@name = 'displayName']"/>
see https://www.w3.org/TR/xslt-30/#unprefixed-qnames. If you have more XSLT elements where you need to use the namespace you can declare xpath-default-namespace
on a common container element but keep in mind that you want to work with two documents with different namespaces so you need to make sure for the elements where you need the default namespace to be empty you don't override it.
Depending on your needs it might be easier in the stylesheet to declare a prefix for the namespace with <xsl:stylesheet xmlns:ecd="http://www.eclipse.org/birt/2005/design" ...>
and to use that prefix then where needed to qualify element names document('inputStack.xml')/ecd:report/ecd:text-property[@name = 'displayName']
in your XPath expressions.
回答2:
<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>
来源:https://stackoverflow.com/questions/51312002/xml-xslt-using-two-xml-input-documents