我有一些SQL死锁,我试图捕获mediaName
。死锁报告是XML格式,但我需要的属性隐藏在XML中,然后是SQL,然后是XML。这是一个例子。
SQL启动的位置为/deadlock/process-list/process/inputbuf
,然后SQL为:
SET DEADLOCK_PRIORITY 8;
EXEC spM_Ext_InsertUpdateXML N'<mediaRecords><media
title="This Is the title" mediaType="0"
creationTime="2018-03-16T00:59:43" origSOM="01:00:00;00" notes="Air Date:
2018-03-18 &#xa;Air Window: 3 &#xa;" mediaName="This is what i need"
><mediaInstances><mediaInstance directory="here"
duration="00:28:40;11" version="1" position="00:00:00;00" mediaSetId="34"
creationStartTime="2018-03-16T00:59:43;25" creationEndTime="2018-03-
16T00:59:43;25"/></mediaInstances><properties><
classifications><classification category="HD" classification="Content
Resolution"/></classifications><markups><markup
name=""><Item duration="00:00:10;00" orderNo="1"
type="Dynamic" som="00:59:50;00" comment=""
name="Segment"/></markup><markup
name="Segment"><markupItem duration="00:08:41;10" orderNo="2"
type="Dynamic" som="01:00:00;00" comment="Main Title and Segment 1 |
ID:SEDC" name="Segment"/></markup><markup
name="Black"><markup
了解XML如何使用<
和>
来表示元素,而<
和>
则增加了复杂性。
我正在尝试从此报告中仅提取mediaName,但无法通过PowerShell获取上述XPath。希望有人可能会有一个想法。我正在使用
$xml = [xml](Get-Content "C:\Users\user\desktop\test.xml")
$xml.SelectNodes('/deadlock/process-list/process/inputbuf') | select mediaName
我还尝试过select-xml
where-object
,但我认为我没有使用正确的$_.[input]
在tomalak和下面的答案的帮助下,这是固定和工作的解析脚本。
#report file location, edited by user when needed
$DeadlockReport = "C:\Users\User\Desktop\xml_report1.xml"
# Create object to load the XML from the deadlock report and find the SQL within
$xml = New-Object xml
$xml.Load($DeadlockReport)
$inputbuf = $xml.SelectNodes('//deadlock/process-list/process/inputbuf')
$value = $inputbuf.'#text'
#find the internal XML and replace bad values, SQL, and truncation with RE
$value = $value -replace "^[\s\S]*?N'","" -replace "';\s*$","" -replace "<markup.*$","</properties></media></mediaRecords>"
#append root elements to $value
$fix = "<root>" + $value + "</root>"
#Load the XML after its been corrected
$payload.LoadXml($fix)
#find the nodes in the xml for mediaName
$mediaName = $payload.SelectNodes('//root/mediaRecords/media/@mediaName')
#iterate through and return all media names.
foreach($i in $mediaName)
{
return $mediaName
}
答案 0 :(得分:0)
你拥有的是:
让我们剥洋葱。
首先,请不要加载像这样的XML文件
# this is bad code, don't use
$xml = [xml](Get-Content "C:\Users\user\desktop\test.xml")
XML具有复杂的文件编码检测功能,您可以通过让Powershell加载文件来使其短路。这可能导致数据无声地中断,因为Powershell的Get-Content
不知道XML文件的实际编码是什么。 (有时上述作品,有时它不会。&#34;它适用于我&#34;并不意味着你做得对,这意味着你的存在幸运的。)
这是正确的方法:
$xml = New-Object xml
$xml.Load("C:\Users\user\desktop\test.xml")
这里XmlDocument
object将负责加载文件并透明地适应它可能具有的任何编码。没有什么可以打破,你不必担心文件编码。
其次,不要让XML文件在文本编辑器中的外观欺骗你。如上所述,/deadlock/process-list/process/inputbuf
包含字符串,就XML而言,<
和>
,当您查看实际情况时,所有其他内容都会出现在那里元素的文本值。
$inputbuf = $xml.SelectSingleNode('/deadlock/process-list/process/inputbuf')
$value = $inputbuf.'#text'
Write-Host $value
会打印这样的东西,即SQL:
SET DEADLOCK_PRIORITY 8;
EXEC spM_Ext_InsertUpdateXML N'<mediaRecords><media
title="This Is the title" mediaType="0"
creationTime="2018-03-16T00:59:43" origSOM="01:00:00;00" notes="Air Date:
2018-03-18 
Air Window: 3 
" mediaName="This is what i need"
><mediaInstances><mediaInstance directory="here"
duration="00:28:40;11" version="1" position="00:00:00;00" mediaSetId="34"
creationStartTime="2018-03-16T00:59:43;25" creationEndTime="2018-03-
16T00:59:43;25"/></mediaInstances><properties><
classifications><classification category="HD" classification="Content
Resolution"/></classifications><markups><markup
name=""><Item duration="00:00:10;00" orderNo="1"
type="Dynamic" som="00:59:50;00" comment=""
name="Segment"/></markup><markup
name="Segment"><markupItem duration="00:08:41;10" orderNo="2"
type="Dynamic" som="01:00:00;00" comment="Main Title and Segment 1 |
ID:SEDC" name="Segment"/></markup><markup
name="Black"><markup ...
</mediaRecords>';
您感兴趣的XML实际上是此SQL中的字符串。如果SQL遵循这种模式......
SET DEADLOCK_PRIORITY 8;
EXEC spM_Ext_InsertUpdateXML N'<...>';
...为了获得XML有效负载,我们需要做三件事:
''
替换为'
(因为''
是SQL字符串中的转义引号)所以
$value = $value -replace "^[\s\S]*?N'","" -replace "';\s*$","" -replace "''","'"
会删除包括N'
和';
在内的所有内容,并将所有重复的单引号(如果有)替换为普通单引号。
根据需要调整正则表达式。用regex替换SQL部分并不完全干净,但是如果预期的输入非常有限,就像在这种情况下一样,它就会这样做。
Write-Host $value
现在我们应该有一个实际 XML的字符串。让我们解析它。这一次,它已经在我们的记忆中,没有任何文件编码需要注意。因此,如果我们直接将其转换为XML,它实际上是正确的:
$payload = [xml]$value
现在我们可以查询您感兴趣的值:
$mediaName = $payload.SelectSingleNode("/mediaRecords/media/@mediaName")
Write-Host $mediaName