2

I have an XML file formatted as:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" version="4.0" indent="yes"/>

<!-- ********* PERMISSIONS ********** -->
<xsl:include href="/Application/Application_interface/permissions.xsl"/>

<!-- match root -->
<xsl:template match="/">
    
    <html>
    <xsl:call-template name="startLogin"/>
    <body onload="javascript:init()" onresize="javascript:change()">
    
    <!-- linked javascript files -->
    <script language="javascript" src="/Application/js_inc/bgColor.js"></script>    
    <script language="javascript" src="/Application/js_inc/login.js"></script>

    <!-- begin content area -->
    <div id="login">
        <form  name="login" action="/Application/servlet/SessionServlet?action=l" method="post" onsubmit="return validateForm()">
        
        <table border="0">
        <tr>
            <td class="label"><xsl:value-of select="document($i18n)/lang/li/userID"/></td>
            <td>
                <!-- Username -->
                <xsl:element name="input">
                    <xsl:attribute name="type">text</xsl:attribute>
                    <xsl:attribute name="name">u</xsl:attribute>
                    <xsl:attribute name="maxLength">20</xsl:attribute>
                    <xsl:attribute name="value">
                    <xsl:value-of select="/ADSMessage/@username"/>
                    </xsl:attribute>
                </xsl:element>      
            </td>
        </tr>
        <tr>
            <td class="label"><xsl:value-of select="document($i18n)/lang/li/password"/></td>
            <td>
                <!-- Password -->
                <xsl:element name="input">
                    <xsl:attribute name="type">password</xsl:attribute>
                    <xsl:attribute name="name">p</xsl:attribute>
                    <xsl:attribute name="maxLength">20</xsl:attribute>
                    <xsl:attribute name="value">
                    <xsl:value-of select="/ADSMessage/@password"/>
                    </xsl:attribute>
                </xsl:element>      
            </td>
        </tr>
        <tr>
            <td colspan="3" class="r">
                <button type="submit" class="btn"><xsl:value-of select="document($i18n)/lang/ch/login"/></button>
            </td>
        </tr>
        </table>
        </form> 
        <div id="avlSession" class="sessionDiv">
        </div>
        <div id="avlDownload" class="downloadDiv">
            <a id="downloadLink" href="" target="_blank"><xsl:value-of select="document($i18n)/lang/dld/btnApplicationClient"/></a> 
        </div>

    </div>
    </body>
    </html>

</xsl:template> 

<xsl:template name="startLogin">
        <xsl:element name="head">
        
        <link rel="shortcut icon" href="/Application/images/favicon.ico" type="image/x-icon"/>

        <xsl:call-template name="pageTitle"/>
        
        <xsl:element name="style">
            <xsl:choose>
                <xsl:when test="/ADSMessage[@splashImage='OEM']">
                    <xsl:text>body{ background: #2F3D6E url(</xsl:text>   <!-- old color  #2F3D6E -->
                    <xsl:text>/Application/images/SplashArtGE.png</xsl:text>
                    <xsl:text>) no-repeat fixed center center; font-family: Arial, Verdana, Helvetica, sans-serif; background-position: 50% 50%; }
                        input{ background-color: #FFFFFF; border-color: #6875A3; color: #000000; width: 15em; }
                        button{ background-color: #4A5788; border: 1px solid #000000; color: #BABECC; padding: 3px; width: 15em; }
                        .label{ text-align: right; font-weight: bold; color: #888888; font-size: 90%; }
                        .r{ text-align: right; }
                        .sessionDiv {margin:240px 0px 0px 0px;}
                        .sessionDiv p{font-weight: bold; color: #BABECC; font-size: 90%;}
                        .downloadDiv a{color: #BABECC; font-size: 75%;}
                    </xsl:text>
                </xsl:when>
                <xsl:when test="/ADSMessage[@splashImage='Application']">
                    <xsl:text>body{ background:  #E8E8E8  url(</xsl:text>   <!-- old color  #304e70 blue logo #ADD8E6-->
                    <xsl:text>/Application/images/SplashArt.png</xsl:text>
                    <xsl:text>) no-repeat fixed center center;  font-family: Arial, Verdana, Helvetica, sans-serif; background-position: 50% 50%;}
                        input{ background-color: #ffffff; border-color: #ffffff; color: #000000; width: 15em; }
                        button{ background-color: #e69100; color: #ffffff; padding: 3px; width: 15em; }
                        .label{ text-align: right; font-weight: bold; color: #888888  ; font-size: 90%; }
                        .r{ text-align: right; }
                        .sessionDiv {margin:240px 0px 0px 0px;}
                        .sessionDiv p{font-weight: bold; color: #e69100; font-size: 90%;}
                        .downloadDiv a{color: #e69100; font-size: 75%;}
                    </xsl:text>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:text>body{ background: #304e70 url(</xsl:text>
                    <xsl:text>/Application/images/SplashArt.png</xsl:text>
                    <xsl:text>) no-repeat fixed center center; font-family: Arial, Verdana, Helvetica, sans-serif; background-position: 50% 50%; }
                        input{ background-color: #ffffff; border-color: #ffffff; color: #000000; width: 15em; }
                        button{ background-color: #e69100; color: #ffffff; padding: 3px; width: 15em; }
                        .label{ text-align: right; font-weight: bold; color: #888888; font-size: 90%; }
                        .r{ text-align: right; }
                        .sessionDiv {margin:240px 0px 0px 0px;}
                        .sessionDiv p{font-weight: bold; color: #e69100; font-size: 90%;}
                        .downloadDiv a{color: #e69100; font-size: 75%;}
                    </xsl:text>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:element>  
        
        <xsl:element name="script">
            <xsl:attribute name="language">javascript</xsl:attribute>
            <xsl:attribute name="src"><xsl:value-of select="$jsLocalization"/></xsl:attribute>
        </xsl:element>
        
    </xsl:element>
</xsl:template>


    
<!-- linked xsl files -->
<xsl:include href="/Application/Application_interface/Application_header.xsl"/>
<xsl:include href="/Application/Application_interface/Application_footer.xsl"/>

</xsl:stylesheet>

I'm trying to write a script to update the second of the two:

<xsl:attribute name="maxLength">20</xsl:attribute>

values to

<xsl:attribute name="maxLength">30</xsl:attribute>

Normally, I know how to do this, but I'm getting stuck because the only difference I see are the lines:

<td class="label"><xsl:value-of select="document($i18n)/lang/li/userID"/></td>

and

<td class="label"><xsl:value-of select="document($i18n)/lang/li/password"/></td>

I can go:

$xml.stylesheet.template.html.body.div.form.table.tr.td."value-of" | Where-Object select -EQ 'document($i18n)/lang/li/password'

But at at that point, I'm already past the node I need to get to, which is

$xml.stylesheet.template.html.body.div.form.table.tr.td.element.attribute

Anyone have an idea on how to do this?

Christopher Cass
  • 817
  • 4
  • 19
  • 31

2 Answers2

3

Solving this via PowerShell's adaption of the XML DOM (where child elements and attributes are surfaced as if they were properties, in a namespace-agnostic fashion - see this answer for background information) is possible, but nontrivial:

$xml.stylesheet.template.html.body.div.form.table.tr.td.
  Where({ $_.'value-of'.select -eq 'document($i18n)/lang/li/password' }).
  NextSibling.
  element.attribute.
  Where({ $_.name -eq 'maxLength' })[0].
  InnerText = 30

The above combines:

  • member-access enumeration for implicitly iterating over all child elements that share a given name

  • the intrinsic .Where() method to filter out an element of interest.

  • the use of the .NextSibling property available on XmlElement instances.

  • assignment to the InnerText property of the element of interest.

    • Note the need to use index [0] on the second .Where() call's result first, despite the fact that only one element matches.
      This is necessary, because .Where() always returns a collection (possibly with just one element), and member-access enumeration only works on getting property values, not also on setting them - see this answer for more information.

Also note the syntactic need to place . (the member-access operator) at the end of each line inside the multi-line command, which PowerShell, which doesn't have an explicit statement terminator, requires to know that the command isn't complete yet.
(Of course, you're free to write the command on a single line, but that will impede readability.)


Conversely, an XPath-based solution via .SelectSingleNode() would be complicated by the need for explicit namespace handling (and, fundamentally, the need to understand XPath syntax).

That said, it certainly makes the part of locating the target element more concise and efficient; see Jack Fleeting's helpful answer.

mklement0
  • 382,024
  • 64
  • 607
  • 775
2

As mentioned by @mklement0, it can be done with xpath:

#declare your namespace
$ns = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$ns.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform")

#select your target    
$target = $xml.SelectSingleNode('//tr[contains(.//td/xsl:value-of/@select,"password")]//xsl:attribute[@name="maxLength"]', $ns)  

#finally, modify it  
$target.InnerText="30"
mklement0
  • 382,024
  • 64
  • 607
  • 775
Jack Fleeting
  • 24,385
  • 6
  • 23
  • 45