开发者

How is XML inheritance typically handled in XSLT?

I have an XML file which uses the base attribute in many places to inherit from data types in multiple documents. What I want is to process the document using XSLT as if it is processing the document with everything inherited. I haven't seen an obvious way to do this although my knowledge of XSLT is pretty minimal.

When I say inheritance I am referring to the XML base attribute which allows a data type to inherit from another data type. For example;

<parameter name="DeviceLog" access="readOnly">
    <description>Vendor-specific log(s).</description>
</parameter>
<parameter base="DeviceLog" access="readOnly" activeNotify="canDeny">
</parameter>

The description tag here should be inherited by the second parameter.开发者_运维问答 So when my XSLT script processes the second parameter it would read it as

<parameter name="DeviceLog" access="readOnly" activeNotify="canDeny">
    <description>Vendor-specific log(s).</description>
</parameter>

maybe this can't be done?

EDIT: The inheritance I was talking about is not standard. It was just something that was created by whoever produced the XML file I was working on. I had to write my own solution to merge all the "inherited" elements and attributes.


XSLT takes an XML document as an input tree and then generates output. When the output is also XML, it effectively transforms the input tree into an output tree. This means it leaves you no room to change the input tree while reading. You also can't really pass around partial results as input to templates as far as I know. So my suggestion would be to perform two XSLT transformations in succession. One to transform the input to your desired virtual intermediate result, the other to perform the actual processing that would be required on this format where inherited structures are collapsed into flat ones.

The XSLT for that first step might use this as a basis:

<?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" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="node()|@*">
        <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
    </xsl:template>
    <xsl:template match="//*[@base]">
        <xsl:variable name="base" select="@base"/>
        <xsl:copy><xsl:copy-of select="./node() | ./@*[local-name() != 'base'] | //*[@name=$base]/@*"></xsl:copy-of><xsl:copy-of select="//*[@name=$base]/node()"/></xsl:copy>
    </xsl:template>
</xsl:stylesheet>

This would transform the following...

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <test name="one" hello="kitty">
        <one hello="world">test</one>
        <two/>
    </test>
    <bogus att="none">
        <test/>
    </bogus>
    <test base="one" run="true" hello="kitty">
        <three/>
    </test>
</root>

... into this:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <test name="one" hello="kitty">
        <one hello="world">test</one>
        <two/>
    </test>
    <bogus att="none">
        <test/>
    </bogus>
    <test name="one" run="true" hello="kitty">
        <three/>
        <one hello="world">test</one>
        <two/>
    </test>
</root>

There's some edge cases to work out. If both the element with the name attribute and the one with the base attribute have attributes with the same name, the processor will detect this and only keep one. This is the case with hello="kitty" here. But if those attributes have different values, the result is hard to predict. You may also wish to suppress the initial name bearing element. To do that, simply add a template that doesn't output anything for elements with a name attribute.

After this transformation, you can apply the second one. I have assumed your "inheritance" nesting is only one deep and only one name appears per base. If this isn't true, this strategy might not work. I'll leave you to handle the details.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜