Home > Blockchain >  Retrieving a text string from a xml document
Retrieving a text string from a xml document

Time:11-24

I am trying to retrieve the string "This is my string" that belongs to text id="short_name

I have tried:

$SVGTemplate          = Get-Content "C:\temp\sample.svg
$SVGTemplate          = [XML]$SVGTemplate
$SVGTemplateShortName = Select-Xml -Xml $SVGTemplate -XPath '/s:svg/s:g/s:g[@id="short_name"]/s:text/text()' -Namespace @{s = "http://www.w3.org/2000/svg"}
$SVGTemplateShortName.node.value

But it returns an empty value. This used to work before and recently broke because I had to redesign the svg graphic.

I have tried to correct the XPath many times and it keeps returning an empty value. What could I be doing wrong? Below is my xml file.

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     viewBox="0 0 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve">
<style type="text/css">
    .st0{fill:#E30613;}
    .st1{fill:#FFFFFF;}
    .st2{fill:#009FE3;}
    .st3{fill:none;}
    .st4{font-family:'MyriadPro-Regular';}
    .st5{font-size:88px;}
    .st6{fill:#008D36;}
</style>
<g id="background">
    <rect id="stroke"  width="500" height="500"/>
    <rect id="Fill" x="12" y="12"  width="476" height="476"/>
</g>
<g id="short">
    <rect id="short_fill" x="12" y="400"  width="476" height="100"/>
    <rect y="412"  width="500" height="88"/>
    <text id="short_name" transform="matrix(1 0 0 1 87.7305 474.4795)" >This is my string</text>
</g>
<g id="hud">
    <rect id="left" x="12" y="12"  width="92" height="76"/>
    <rect id="right" x="396" y="12" width="92" height="76"/>
</g>
<g id="graphic">
    <g id="Card_Symbl">
        <g id="Layer_10">
            <polygon  points="309.9,387.1 396.3,124.5 303.1,105.8 96.5,251.1             "/>
        </g>
    </g>
</g>
</svg>

CodePudding user response:

If you want to locate an element by its full path, an easier way is to use PowerShell's member access:

$SVGTemplate.svg.g.text | Where-Object id -eq 'short_name' | ForEach-Object '#text'

... or more succinct, using intrinsic .Where method:

$SVGTemplate.svg.g.text.Where{ $_.id -eq 'short_name'}.'#text'

XPath does have an advantage if you want to locate an element regardless of how deep it is nested (relative path, introduced by double slash):

$SVGTemplate | 
    Select-Xml -XPath '//s:text[@id="short_name"]' -Namespace @{s = "http://www.w3.org/2000/svg"} | 
    ForEach-Object { $_.Node.'#text' }

Of course it also works using the absolute path (introduced using single slash), but is much more lengthy than its member access counterpart:

$SVGTemplate | 
    Select-Xml -XPath '/s:svg/s:g/s:text[@id="short_name"]' -Namespace @{s = "http://www.w3.org/2000/svg"} | 
    ForEach-Object { $_.Node.'#text' }

CodePudding user response:

The original XPath expects a <g> tag with an id attribute and a value of "short_name"... however the XML does not contain such a path. Was it supposed to read `/s:text[@id="short_name"]?

Other than that, yes anyone can use PS´s "human-friendly" access methods... though there is a bit of an inherent danger there when there is no schema attached to the XML or when trying to access optional nodes that might or might not be there for a given path.

PS works with lists. XML paths break when using $xmlDoc.tagA.tagB.tagC notation; assuming this is not $null and is a list longer than exactly one (1) node then we have no way of telling where in the XML and under possibly what conditions we got those nodes from.

... When in doubt: don't.

  • Related