XML - XSLT - Using two XML input documents

陌路散爱 提交于 2019-12-25 00:24:30

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!