Problem
I started working with OAGIS schemas . The schemas are very complex and many have over 1000 entities (elements, attributes, sequences, etc…) inside.
Let’s say I’m doing a BizTalk map, and I want to see if the schema has a field called “RequestedDeliveryDate”. Or maybe I want to find all the dates. You can’t do that in BizTalk Schema editor. You can open the .xsd schema file itself in NotePad++ and search, but it’s hard to read, and hard to find out where you are in the hierarchy.
Solution
Write your own program to list out all the elements, attributes etc… with the hierarchy.
For now, I’m just using “Write-Host” statements, and when the script runs, I can copy/paste the output window to NotePad++. From there, I can do normal search commands, or even RegEx search commands.
I thought about making the script look for the element pattern, but to me, it was easier to do that in NotePad++.
Code
<pre>
#
# Author: Neal Walters
# Date: 1/17/2020
# Descr: Help find element/attribute names in the huge OAGIS schemas
#
# Return the value of an attribute from a given xmlNode
function GetXmlElementsAttributeValue($node, $AttributeName)
{
# Try and get the node.
#$node = Get-XmlNode -XmlDocument $XmlDocument -NodePath $ElementPath -NamespaceURI $NamespaceURI -NodeSeparatorCharacter $NodeSeparatorCharacter
# If the node and attribute already exist, return the attribute's value, otherwise return null.
if ($node -and $node.$AttributeName) { return $node.$AttributeName } else { return $null }
}
# Do the recursion, looping through all elements and their children
function explodeSchema($passNode)
{
$depthCounter = $depthCounter + 1
$indent = "*" * $depthCounter
#Write-Host "$indent explodeSchema depth=$depthCounter NodeNameAttrValue=$($passNode.Name)"
$nodes = $passNode.SelectNodes($xpathEl)
#Write-Host "nodes count=$($nodes.count)"
foreach ($node in $nodes)
{
$totalNodeCount = $totalNodeCount + 1
$NodeNameAttrValue = GetXmlElementsAttributeValue $node "name"
$ref = GetXmlElementsAttributeValue $node "ref"
$showRef = ""
if ($ref.length -ge 1)
{
$showRef = "ref=$ref "
}
if ($node.LocalName -eq "element" -or $node.LocalName -eq "attribute")
{
$showName = "$($node.LocalName)=$($node.Name)"
}
else
{
$showName = $node.LocalName
}
Write-host "$indent $showName $showRef "
explodeSchema $node #go recursive here
}
$depthCounter = $depthCounter - 1
}
cls
$schemaFilename = "C:\YourFolderName\YourSchemaName.xsd"
$xpathEl = "*[local-name()='element' or local-name()='complexType' or local-name()='group' or local-name()='sequence' or local-name()='attribute']";
[xml] $xmlDoc = Get-Content $schemaFilename
$node = $xmlDoc.SelectSingleNode("//*") #get us positioned on the root element
Write-Host "Root Node:" + $node.Name
$depthCounter = 0
$totalNodeCount = 0
explodeSchema $node
Write-Host "totalNodeCount=$totalNodeCount" #bug here, count shows zero??
</pre>
Sample Output
Note: The number of asterisks tell you what depth you are in the hierarchy.
<pre>
Root Node: + xs:schema
* element=X12_00401_204
** complexType
*** sequence
**** element=ST
***** complexType
****** sequence
******* element=ST01
******* element=ST02
******* element=ST03
**** element=xs:element ref=B2
**** element=xs:element ref=B2A
**** element=xs:element ref=L11
**** element=xs:element ref=G62
...
* element=N2
** complexType
*** sequence
**** element=N201
**** element=N202
* element=N3
** complexType
*** sequence
**** element=N301
**** element=N302
</pre>
What else could be done?
Ideas for the future include:
1. Showing the field type (string, int, decimal, etc…)
2. For EDI fields, could show other attributes such as N2 or R5
3. Showing min/max occurs
4. Add ability to find field containing a given lookup string (then show the parents when a match is found). For example, show all “date” elements/attributes.
Other keywords to help find this post:
1. Recursive XPath against an XSD schema
2. XSD Schema Recursion
3. Explode Schema element names using recursion
4. Extract all schema element names to a file using a script