LazyCaterinxxx
LazyCaterinxxx

Reputation: 33

Accessing XML data using Xpath and GetElementbyID

I am new powershell and not very good at it. Please be patient if I am using the wrong words.

Lets say the content of my.Xml file is:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
    <!ENTITY ns_extend "http://ns.adobe.com/Extensibility/1.0/">
    <!ENTITY ns_ai "http://ns.adobe.com/AdobeIllustrator/10.0/">
    <!ENTITY ns_graphs "http://ns.adobe.com/Graphs/1.0/">
    <!ENTITY ns_vars "http://ns.adobe.com/Variables/1.0/">
    <!ENTITY ns_imrep "http://ns.adobe.com/ImageReplacement/1.0/">
    <!ENTITY ns_sfw "http://ns.adobe.com/SaveForWeb/1.0/">
    <!ENTITY ns_custom "http://ns.adobe.com/GenericCustomNamespace/1.0/">
    <!ENTITY ns_adobe_xpath "http://ns.adobe.com/XPath/1.0/">
]>
<svg version="1.1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;"
     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">
<switch>
    <foreignObject requiredExtensions="&ns_ai;" x="0" y="0" width="1" height="1">
        <i:aipgfRef  xlink:href="#adobe_illustrator_pgf">
        </i:aipgfRef>
    </foreignObject>
    <g i:extraneous="self">
        <g id="Background">
            <rect style="fill:#FFFFFF;stroke:#000000;stroke-miterlimit:10;" width="500" height="500"/>
        </g>
        <g id="Guides" style="display:none;">
            <rect y="400.25" style="display:inline;fill:none;" width="500" height="149.75"/>
        </g>
        <g id="Card_Symbl">
            <g id="Layer_10">
                <polygon style="fill:#E30613;" points="436.87,87.48 31.42,175.37 192.19,246.84 214.13,403.67                "/>
            </g>
        </g>
        <g id="Card_Modifier">
            <rect y="424" style="fill:#009FE3;" width="500" height="76"/>
        </g>
        <g id="Card_Short_Name">
            <text transform="matrix(1 0 0 1 32.4003 480.7129)" style="fill:#FFFFFF; font-family:'MyriadPro-Regular'; font-size:70px;">Hello, World</text>
        </g>
        <g id="Card_HUD">
            <g id="Bottom_Right">
                <rect x="408" y="348" width="92" height="76"/>
                <text transform="matrix(1 0 0 1 420.9258 411)" style="fill:#FFED00; font-family:'MyriadPro-Regular'; font-size:75px;">-</text>
            </g>
            <g id="Bottom_Left_00000030455522749116218520000014918866582792132275_">
                <rect y="348" width="88" height="76"/>
                <text transform="matrix(1 0 0 1 5 411)" style="fill:#FFED00; font-family:'MyriadPro-Regular'; font-size:75px;">1</text>
            </g>
            <g id="Top_Right">
                <rect x="408" width="92" height="76"/>
                <text transform="matrix(1 0 0 1 421 60)" style="fill:#FFED00; font-family:'MyriadPro-Regular'; font-size:75px;">-</text>
            </g>
            <g id="Top_Left">
                <rect style="fill:#008D36;" width="92" height="76"/>
                <text transform="matrix(1 0 0 1 12 60)" style="fill:#FFED00; font-family:'MyriadPro-Regular'; font-size:75px;">-</text>
            </g>
        </g>
    </g>
</switch>
</svg>

The file is imported like this:

$xmlSample = Get-Content -Raw -Path ".\FlashCard V4.svg"
$XML = [xml]$xmlSample

I am trying to navigate its structure. I have tried:

$xml.GetElementById(Card_Symbl)

Powershell returns nothing. I then tried :

$var = Select-Xml -Xml $XML -XPath "/svg/switch"

Again, Powershell returns nothing.

I managed to figure this out:

$xml.svg.Switch.g.g.g

It works as expected, Powershell returns all the data at that "level" but I dont see this being that versatile though. In a medium to large data set, this would be daunting.

Reading from the docs and this book I am learning from, I really like the Select-Xml -Xml $XML -XPath "/svg/switch" method. it makes things as simple as navigating a directory or a folder in file explorer.

If I can ask, can I see one working example of :

$xml.GetElementById(Card_Symbl)

And one working example of:

$var = Select-Xml -Xml $XML -XPath "/svg/switch"

Where both cases use my above xml sample and will return some the data that is targeted.

I'm open to suggestion as long as they are in Powershell.

Upvotes: 2

Views: 292

Answers (2)

jdweng
jdweng

Reputation: 34421

Using PowerShell with xml linq

using assembly System 
using assembly System.Xml.Linq 

$Filename = "c:\temp\test.xml"
$xDoc = [System.Xml.Linq.XDocument]::Load($Filename)
$root = [System.Xml.Linq.XElement]$xDoc.Root
$ns = [System.Xml.Linq.XNamespace]$root.GetDefaultNamespace()

$gs =  $xDoc.Descendants($ns + "g")
$cardSymbol = [System.Linq.Enumerable]::Where($gs, [Func[object,bool]]{ param($x) [string]$x.Attribute("id").Value -eq "Card_Symbl"})
Write-Host "cardSymbol = " $cardSymbol

Upvotes: 0

David Browne - Microsoft
David Browne - Microsoft

Reputation: 88852

That document has a default namespace, so you must namespace-qualify your node references, eg

Select-Xml -Xml $XML -XPath "/s:svg/s:switch" -Namespace @{s = "http://www.w3.org/2000/svg"}

To retrieve "Hello, World" you would use an XPath like this:

$e = Select-Xml -Xml $XML -XPath '/s:svg/s:switch/s:g/s:g[@id="Card_Short_Name"]/s:text/text()' -Namespace @{s = "http://www.w3.org/2000/svg"}
$e.Node.Value

The key bit is this expression

s:g[@id="Card_Short_Name"]

Which finds s:g elements with an id attribute of "Card_Short_Name".

The other thing to note is that XmlElement doesn't have a .Value, you have to grab the text node under the element to extract the value with s:text/text().

Upvotes: 2

Related Questions