Making use of XSLT to add an attribute

Users who are viewing this thread

Hello!
I'm a newbie modder making use of XSLT to modify some files, more specifically the description of some towns and villages. The following lines are an example of how I successfully replaced a description of a village.

XML:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match='Settlement[@id="castle_village_S3_1"]/@text'>
        <xsl:attribute name='text'>NEW DESCRIPTION</xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

The problem I have is when a town, village or castle is lacking a text description attribute in the first place. Then those lines don't work. I know you can add such attributes by using a normal xml file, but I'd much rather prefer if I could do it in the xslt file. Since I'm a newbie modder with no programing background, I rely on looking at how other mods make stuff work, but in this case I've not found any examples. Could anyone help me formulate what those lines should look like for this to work? Would be much appreciated!
 
Solution
Hello again. I can now proudly say that after many trial and errors, I've found the solution myself! In my eyes as a newbie modder, I think it could be valuable to know, so I'll post it here as documentation for anyone else having the same question.
XML:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match='Settlement[@id="castle_village_S3_1"]'>
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="text">NEW DESCRIPTION</xsl:attribute>...
Hello again. I can now proudly say that after many trial and errors, I've found the solution myself! In my eyes as a newbie modder, I think it could be valuable to know, so I'll post it here as documentation for anyone else having the same question.
XML:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match='Settlement[@id="castle_village_S3_1"]'>
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="text">NEW DESCRIPTION</xsl:attribute>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>
 
Upvote 1
Solution
Hi everybody! I'm trying to make 2 mods work that replace different attributes in <Culture> (spcultures.xml ), using xslt - mod #1 replaces basic_troop, and #2 (mine) replaces only the name and description of cultures ("name" and "text"). But when loading both mods, the game crashes with the error "Object reference not set to an instance of an object" in mod #1. I can't figure out why. After all, these xslt replace different attributes.
The code as in the post above also tried, the result is the same - everything works separately, but when loading two mods it crashes with the same error.
xslt #1
XML:
    <xsl:template match="Culture[@id='aserai']">
        <Culture>
            <xsl:for-each select="@*">
                <xsl:attribute name="{name()}">
                    <xsl:value-of select="." />
                </xsl:attribute>
            </xsl:for-each>
            <xsl:attribute name="elite_basic_troop">NPCCharacter.aserai_mameluke_regular</xsl:attribute>
            <xsl:apply-templates select="node()"/>
        </Culture>
    </xsl:template>

xslt #2
XML:
    <xsl:template match="Culture[@id='aserai']/@name">
        <xsl:attribute name="name">new name</xsl:attribute>
    </xsl:template>
    <xsl:template match="Culture[@id='aserai']/@text">
        <xsl:attribute name="text">new text</xsl:attribute>
    </xsl:template>
 
Upvote 0
AFAIK xslt edits a vanilla xml. Accordingly, the last mod loaded will make only its edit of the vanilla spcultures.xml, overwriting the edit made by the previously loaded mod. As a consequence that mod will crash as it expects something in spcultures,xml that’s no longer there. You probably need both edits in the same xslt by loading a third mod last with just that.
 
Upvote 0
Tried another option. In one mod, I removed all the edits and made them to spcultures.xml and its xslt of the second mod (Feudal Warfare mod). That is, the Culture attributes are changed in the native file: name, text, and elit_basic_troop. Same result - game crash. Tried to just change the attribute to name="Roman" without inclusion in xslt - crash too.
 
Upvote 0
Damn! Everything worked out)) My mistake was that I forgot to specify the {=...} prefix in the value of my attributes in xslt, which is used for translation and was present in the xml file... in the end, I just deleted it everywhere and everything worked. Used the following code:
XML:
<xsl:template match="Culture[@id='empire']">
        <Culture>
            <xsl:for-each select="@*">
                <xsl:attribute name="{name()}">
                    <xsl:value-of select="." />
                </xsl:attribute>
            </xsl:for-each>
            <xsl:attribute name="name">Roman</xsl:attribute>
            <xsl:attribute name="text">new text</xsl:attribute>
            <xsl:attribute name="elite_basic_troop">NPCCharacter.imperial_trained_infantryman</xsl:attribute>
            <xsl:apply-templates select="node()"/>
        </Culture>
    </xsl:template>
 
Upvote 0
Damn! Everything worked out)) My mistake was that I forgot to specify the {=...} prefix in the value of my attributes in xslt, which is used for translation and was present in the xml file... in the end, I just deleted it everywhere and everything worked. Used the following code:
XML:
<xsl:template match="Culture[@id='empire']">
        <Culture>
            <xsl:for-each select="@*">
                <xsl:attribute name="{name()}">
                    <xsl:value-of select="." />
                </xsl:attribute>
            </xsl:for-each>
            <xsl:attribute name="name">Roman</xsl:attribute>
            <xsl:attribute name="text">new text</xsl:attribute>
            <xsl:attribute name="elite_basic_troop">NPCCharacter.imperial_trained_infantryman</xsl:attribute>
            <xsl:apply-templates select="node()"/>
        </Culture>
    </xsl:template>
Congratulations :smile:
 
Upvote 0
Hi all! Using xslt, trying to change some attributes of settlements on the Europe Campaign Map - change the name and owner of the castle, and add a text with a description of the castle to the encyclopedia. The name and owner attributes are changed via xslt (i.e. there is no need to additionally create an xml file). But the text attribute does not want to appear, I tried all possible xslt entries (3 different working options). But if make changes via xml+xslt (i.e., completely prescribe the "castle" element with changed attributes in xml), everything works. What could be the matter? I wouldn't want to create a lot of files to replace multiple attributes.
 
Upvote 0
Back
Top Bottom